Deploy a Full-Stack Next.js App with Postgres, Background Jobs, and File Uploads
A production Next.js application often needs more than a single service. This guide walks through deploying a full-stack Next.js app on Railway with a Postgres database, a Redis-backed background worker, and file uploads via storage buckets, all in a single project.
Best for: SaaS applications, dashboards, and internal tools that need a database, async job processing, and file handling alongside a Next.js frontend.
Architecture overview
This setup uses five components in one Railway project:
- Next.js service handles SSR, API routes, and serves the frontend.
- Postgres stores application data.
- Redis serves as the job queue backend.
- Worker service processes background jobs from Redis.
- Storage bucket stores user-uploaded files.
All services communicate over private networking. The Next.js service and worker share the same codebase but run different entry points.
Prerequisites
- A Railway account
- A Next.js application (App Router or Pages Router)
- Railway CLI installed (optional)
1. Create the project and databases
- Create a new project on Railway.
- Add a PostgreSQL database: click + New, then Database, then PostgreSQL.
- Add a Redis database: click + New, then Database, then Redis.
Both databases are accessible to any service in the project via reference variables.
2. Deploy the Next.js app
Deploy your Next.js app as the primary service. If you have not deployed Next.js on Railway before, see the Next.js deployment guide for the full walkthrough.
Key configuration for production:
- Set
output: "standalone"innext.config.js:
This creates a minimal production build that does not require node_modules at runtime.
- Set the following variables on the Next.js service:
- Add a pre-deploy command for database migrations:
This runs migrations before the new version starts serving traffic, preventing downtime from schema changes.
3. Add Prisma and the database schema
Install Prisma and initialize it:
Define your schema in prisma/schema.prisma:
Generate the client and create the initial migration locally:
Commit the migration files. Railway runs npx prisma migrate deploy on each deploy via the pre-deploy command.
4. Add file uploads via storage buckets
- Create a storage bucket in your Railway project: click + New, then Bucket.
- Add bucket credentials to your Next.js service using reference variables or the automatic credential injection described in Storage Buckets.
Create an API route that generates presigned upload URLs:
The frontend requests a presigned URL, then uploads the file directly to the bucket. This avoids routing large files through the Next.js server. For the full pattern, see Use Storage Buckets for Uploads.
5. Add a background worker
Background jobs handle work that should not block the HTTP response: sending emails, processing uploads, generating reports, calling external APIs.
Set up BullMQ
Install BullMQ:
Create a shared queue definition:
Enqueue jobs from Next.js API routes
Create the worker entry point
Create a separate entry point for the worker:
Deploy the worker as a separate service
- In your Railway project, click + New, then GitHub Repo, and select the same repository.
- Rename the service to "Worker."
- Set the start command to
npx tsx worker.ts. - Add the same database variables:
The worker does not need a public domain. It connects to Redis over private networking and processes jobs continuously.
For more on background processing patterns, see Choose between cron jobs, workers, and queues.
6. Wire services together
Your Railway project now has five components. Here is how they connect:
- Next.js reads
DATABASE_URLandREDIS_URLfrom reference variables. It serves the frontend, handles API routes, and enqueues jobs. - Worker reads the same
DATABASE_URLandREDIS_URL. It dequeues and processes jobs. - Postgres and Redis are shared by both services via reference variables.
- Bucket credentials are set on the Next.js service (and the worker, if it needs to read/write files).
All inter-service communication uses private networking. No public domains are needed for Postgres, Redis, or the worker.
7. Production hardening
Health checks
Add a health check to the Next.js service. Next.js serves a default health endpoint, or create a custom one:
Restart policy
Set the restart policy to automatically restart services that crash.
Environment separation
Use Railway environments to run staging and production instances. Each environment gets its own databases and variables.
Pre-deploy migrations
The pre-deploy command (npx prisma migrate deploy) runs before the new container starts serving traffic. If the migration fails, the deployment does not proceed and the previous version keeps running.
Next steps
- Next.js deployment guide - Detailed deployment options for Next.js.
- Use Storage Buckets for Uploads - Full file upload patterns.
- Choose between cron jobs, workers, and queues - Background processing architecture.
- Deploy a SaaS Backend - Similar architecture without Next.js.
- Manage environment variables - Handle build-time vs runtime variables.
- Choose between SSR, SSG, and ISR - Pick the right rendering strategy.