how to self-host next.js 16 with docker and sqlite - By Sourav Mishra (@souravvmishra)
save a ton of money by self-hosting next.js 16. here is a simple guide using docker, sqlite, and a basic vps.
okeyy, let's talk about the "vercel tax". vercel is awesome, but it can get super expensive. the good news? self-hosting next.js 16 is now super easy thanks to its standalone output.
i am sourav mishra, and we use this exact strategy at codestam technologies to host our internal tools for pennies.
why self-host?
it's all about control and cost. a simple $5 vps can handle thousands of requests per second if you do it right. you really don't need a crazy expensive cloud setup for most things.
step 1: the dockerfile
the trick here is a multi-stage build. it keeps your docker image around 100mb instead of a massive 1gb.
# Dockerfile
FROM node:20-alpine AS base
FROM base AS deps
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm ci
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
EXPOSE 3000
CMD ["node", "server.js"]
don't forget to set
output: 'standalone'in yournext.config.mjs!
step 2: storing data in sqlite
you probably don't need postgres. sqlite (or turso/libsql) is insanely fast because it's just a file on your server.
at codestam technologies, we handled 50k+ requests a day on a single $5 vps using this setup.
// lib/db.ts
import Database from 'better-sqlite3';
const db = new Database('sqlite.db');
db.pragma('journal_mode = WAL');
export default db;
when you deploy, just mount a volume so your sqlite.db doesn't get deleted when docker restarts.
step 3: the docker-compose file
use docker-compose.yml to run the container and restart it if it crashes.
version: '3'
services:
nextjs-app:
build: .
restart: always
ports:
- "3000:3000"
volumes:
- ./data:/app/data
step 4: setting up nginx
never expose node.js directly to the web. use nginx as a reverse proxy to handle ssl and forward traffic.
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
vercel vs self-hosting
| Feature | Vercel | Self-Hosted (Docker) |
|---|---|---|
| cost | free tier, then gets pricey fast | fixed like $5-$10/mo |
| setup | almost nothing | gotta learn docker & nginx |
| scaling | automatic | upgrade your vps |
| control | not much | full root access |
wrapping up
self-hosting next.js 16 is a great choice if you want to save money. docker and sqlite make it super solid and you own the whole thing.
worried about seo? read my next.js seo guide.
wanna speed up your dev workflow? see why turbopack is amazing.
written by sourav mishra. building fast things at codestam technologies.