Unable to read static files from public directory in Remix Shopify app

I’m working on a Remix Shopify application and trying to read some static text files that contain data I need to process. I have a couple of .txt files stored in my /public/ folder - one contains a list of regions and another has some configuration data.

My goal is to load this data inside a .tsx component so I can transform it and inject it into the merchant’s theme as custom snippets.

However, when I try to access these files from my Remix route file, I keep getting parsing errors. Here’s what I’m attempting:

const regionsData = await fetch("/regions.txt");

This throws an error like:

remix │ Error: Failed to parse URL from /regions.txt

I assumed files in the /public/ directory would be accessible directly, but it seems like there’s something I’m missing about how Remix handles static assets in Shopify apps.

What’s the proper approach for accessing .txt files (and other static assets like images) from within a Remix route component? I’m specifically working in the main route file but need to read these files server-side to process their contents.

yeah, this is a classic remix shopify app issue. you can’t fetch from server context like that. skip the fetch and import your files at build time or use dynamic imports instead. move those txt files from public to app/data, then import them directly: import regionsData from '~/data/regions.txt'. or grab a bundler plugin that handles txt imports properly.

Both approaches work, but they’re a pain to maintain as your app grows. Every new data file means more manual coding.

I hit this same problem building merchant tools that processed config files and injected theme snippets. The tricky part isn’t reading files - it’s managing the entire workflow: reading, processing, transforming, and deploying snippets across multiple stores.

What fixed it for me was an automated pipeline that watches for file changes, processes the data, and handles Shopify API calls automatically. No more manual file reading or hardcoded paths.

You can build something similar with Latenode. Set up a workflow that monitors your data files, processes changes automatically, and updates your Shopify themes. It handles file operations, data transformation, and API calls in one pipeline.

Then you can focus on your app logic instead of fighting file system operations every time you add new regions or config data.

This happens because fetch() with relative paths breaks in server-side Remix code. The server can’t resolve /regions.txt to your public folder during SSR. I hit the same issue building a Shopify app. Use Node.js file system operations instead of fetch for server-side file reading. Import fs and path modules, then read files directly: typescript import { readFileSync } from 'fs'; import { join } from 'path'; const regionsData = readFileSync(join(process.cwd(), 'public', 'regions.txt'), 'utf-8'); This works great in Remix loaders and actions. Public directory is for client-side assets that browsers request directly, not server-side file reading.

try using the full URL for the fetch. had that prob too with my shopify app - switched to fetch("http://localhost:3000/regions.txt") and it worked. the server needs the complete URL for ssr. not ideal, but it’s a quick fix!

The problem is that Remix’s server can’t access your public directory during SSR. There’s no browser context to resolve relative URLs on the server side. I encountered this same issue while developing Shopify apps requiring access to merchant data files. Your solution depends on the nature of the data. For static files that seldom change, you can utilize Remix’s asset imports or place files in your app directory for direct imports. However, if the files are dynamic and frequently updated, consider implementing file uploads to a database or cloud storage. The public directory is intended for client-side assets rather than server-side processing. Alternatively, using environment variables or a simple database table for configuration data is more scalable as your application grows.

Had the same headache building my first Remix Shopify app. You’re mixing server-side and client-side contexts. When Remix runs your loader or action on the server, there’s no base URL to resolve relative paths like /regions.txt. The server doesn’t know what domain or protocol to use. I treated this as two separate problems. For static data that rarely changes, I moved everything to the app directory and imported directly. For files that need regular updates or get shared across the app, I used the filesystem approach with proper error handling. One gotcha: if you’re planning to let merchants upload their own data files later, the public directory approach won’t scale. You’ll need file uploads to proper storage anyway. Start with a simple JSON import from your app directory, then migrate to database storage or cloud files when you need dynamic updates.