Next.js + Railway + FastAPI + Tailwind CSS — A production-ready full-stack template.
Built with Next.js 15, FastAPI, PostgreSQL, Redis, arq workers, and Tailwind CSS 4. Deploys to Railway with one click.
- Backend: FastAPI, SQLAlchemy 2.0 (async), PostgreSQL, Redis, arq workers
- Frontend: Next.js 15 (App Router), React 19, Tailwind CSS 4, Zustand
- Auth: JWT access/refresh tokens, RBAC (roles + permissions)
- Infra: Docker multi-stage builds, Railway deployment configs
- Python 3.12+
- Node.js 22+
- uv (Python package manager)
- Docker & Docker Compose
cp .env.example .env
make build
make start- API: http://localhost:8000
- API docs: http://localhost:8000/docs
- Frontend: http://localhost:3000
Backend:
cd api
uv sync
cp ../.env.example .env
uv run alembic upgrade head
uv run python scripts/seed_roles.py
uv run uvicorn app.main:create_app --factory --reload --port 8000Frontend:
cd frontend
npm install
cp .env.example .env.local
npm run devnrft/
├── api/ # FastAPI backend
│ ├── app/
│ │ ├── api/v1/ # Route handlers
│ │ ├── auth/ # JWT, passwords, RBAC
│ │ ├── core/ # Exceptions, enums, locking
│ │ ├── middleware/ # Request ID, audit, rate limit, CORS
│ │ ├── models/ # SQLAlchemy models
│ │ ├── repositories/ # Data access layer
│ │ ├── schemas/ # Pydantic schemas
│ │ ├── services/ # Business logic
│ │ └── workers/ # arq background tasks
│ ├── alembic/ # Database migrations
│ └── tests/ # pytest suite
│
├── frontend/ # Next.js frontend
│ └── src/
│ ├── app/ # App Router pages
│ ├── components/ # UI components
│ ├── hooks/ # React hooks
│ ├── services/ # API client + mock layer
│ ├── stores/ # Zustand state
│ └── types/ # TypeScript types
│
├── docker-compose.yml # Base services
├── docker-compose.dev.yml # Dev overrides
├── docker-compose.prod.yml # Prod overrides
└── Makefile # Dev commands
| Command | Description |
|---|---|
make build |
Build all Docker images |
make start |
Start all services |
make stop |
Stop all services |
make clean |
Stop and remove volumes |
make logs |
Tail all logs |
make test |
Run all tests |
make test-unit |
Run unit tests |
make test-cov |
Run tests with coverage |
make lint |
Run linters (ruff, mypy, eslint) |
make format |
Auto-format Python code |
make migrate |
Run database migrations |
make migrate-create |
Create new migration |
make seed |
Seed default roles and admin user |
GitHub Actions runs on every push to main and every PR:
| Job | What it checks |
|---|---|
| Backend Lint | ruff check + ruff format --check |
| Backend Test | pytest (unit + integration) |
| Frontend Lint | eslint src/ |
| Frontend Build | next build |
All four jobs must pass before Railway deploys.
Railway auto-deploys when CI passes. Setup:
- Create a new Railway project
- Add a PostgreSQL database service
- Add a Redis service
- Deploy the API service:
- Root directory:
api/ - Railway auto-detects
railway.toml - Set environment variables:
DATABASE_URL,REDIS_URL,SECRET_KEY
- Root directory:
- Deploy the Worker service:
- Root directory:
api/ - Use
railway-worker.toml(rename torailway.tomlor configure in dashboard) - Same environment variables as API
- Root directory:
- Deploy the Frontend service:
- Root directory:
frontend/ - Set
NEXT_PUBLIC_API_URLto the Railway API URL
- Root directory:
- Enable "Wait for CI" in each Railway service's settings so Railway waits for GitHub Actions to pass before deploying
Alternatively, uncomment the deploy jobs in .github/workflows/ci.yml to deploy via Railway CLI. This requires a RAILWAY_TOKEN secret and service IDs configured in your GitHub repo settings.
| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
— | PostgreSQL connection (asyncpg) |
REDIS_URL |
— | Redis connection |
SECRET_KEY |
— | JWT signing key |
JWT_ALGORITHM |
HS256 |
JWT algorithm |
ACCESS_TOKEN_EXPIRE_MINUTES |
30 |
Access token TTL |
REFRESH_TOKEN_EXPIRE_DAYS |
7 |
Refresh token TTL |
CORS_ORIGINS |
http://localhost:3000 |
Allowed origins |
DEBUG |
false |
Debug mode |
PORT |
8000 |
API port |
NEXT_PUBLIC_API_URL |
http://localhost:8000/api |
API URL for frontend |
NEXT_PUBLIC_USE_MOCKS |
false |
Enable mock services |
This template follows a UI/UX-first development workflow:
- Design the UI — Build components with mock data first
- Define types — Create TypeScript interfaces in
src/types/api.ts - Create mock services — Return hardcoded data in
src/services/mock/ - Build & polish — Iterate on design without backend dependencies
- Implement backend — Create FastAPI endpoints matching the types
- Replace mocks — Swap mock services for real API calls
Set NEXT_PUBLIC_USE_MOCKS=true to enable the mock service layer. See frontend/src/services/mock/README.md for details.
After seeding, the default admin account is:
- Email:
admin@example.com - Password:
changeme
Change these immediately in production.
MIT