A highly flexible, secure, and production-ready Docker base image for Next.js applications, with first-class support for Prisma.
Docker Hub Image: ghcr.io/gecut/nextjs/with-prisma:<tag>
- Key Features
- Prerequisites
- How to Use in Your Project
- Configuration
- Architectural Philosophy
- Development Guide
- Roadmap
- Contributing
- Frequently Asked Questions (FAQ)
- License
- Author
- 🔒 Security First: Runs the application as a non-root user (
nextjs) to minimize security risks. - 🧩 Modular & Extensible: Uses a script-based startup system. Simply add or remove shell scripts in the
/scriptsdirectory to customize the startup sequence. - ⚡ Optimized for Production: Built with multi-stage builds to create a small and efficient final image.
- 🛠️ Flexible Package Manager: Supports
pnpm,yarn, andnpmout of the box. - 🔄 Built-in Revalidation: Includes a mechanism to automatically revalidate Next.js pages on startup.
- 🗃️ Prisma Ready: Automatically runs database migrations (
prisma migrate deploy) during the startup sequence.
To use this Docker image, you will need the following tools installed on your local machine:
- Docker
- Docker Compose (recommended for local development)
Integrating this base image into your Next.js project is straightforward.
Create a Dockerfile in the root of your Next.js project with the following content. The base image handles all the heavy lifting.
# Use the desired version tag. Using 'latest' is convenient but pinning to a specific version is safer for production.
FROM ghcr.io/gecut/nextjs/with-prisma:latest
# Copy your application code into the image.
# The base image knows where to put it.
COPY . .
Open your terminal and run the build command:
docker build -t my-awesome-next-app .To use a different package manager (default is pnpm):
# For Yarn
docker build --build-arg PACKAGE_MANAGER=yarn -t my-awesome-next-app .
# For NPM
docker build --build-arg PACKAGE_MANAGER=npm -t my-awesome-next-app .The easiest way to run the container is with docker-compose.
Create a docker-compose.yml file:
version: '3.8'
services:
app:
# Use the image you just built
image: my-awesome-next-app
build: .
ports:
- "3000:3000"
environment:
# See the Configuration section for all available variables
- PORT=3000
- REVALIDATE_SECRET=YOUR_SUPER_SECRET_TOKEN
- UPLOADS_STORAGE_PATH=/app/public/uploads
volumes:
# Persist uploaded files by mounting a volume
- ./public/uploads:/app/public/uploadsThen, start your application:
docker-compose upThe behavior of the startup scripts can be controlled via these environment variables:
| Variable | Description | Default |
|---|---|---|
PORT |
The port the Next.js server will listen on. | 3000 |
REVALIDATE_SECRET |
A secret token used to secure the /api/revalidate endpoint. If not set, revalidation is skipped. |
(none) |
*_STORAGE_PATH |
Any variable ending with this suffix will be treated as a path whose permissions need to be fixed for the nextjs user. |
(none) |
ORIGIN |
The base URL for the revalidation request (e.g., your production domain). | http://localhost:3000 |
- Orchestrator Pattern (
setup.sh): The mainsetup.shscript acts as an orchestrator that simply executes every*.shfile within the/scriptsdirectory in numerical/alphabetical order. - Modular Startup (
/scriptsdirectory): Every distinct startup task (fixing permissions, running migrations) is isolated in its own script for clarity, extensibility, and maintainability. - Security through Privilege Separation: The container starts as
rootto perform setup tasks, but the final script (99-entrypoint.sh) usessu-execto drop privileges and execute the application as the unprivilegednextjsuser.
This section is for those who want to contribute to or modify this base image project itself.
.
├── Dockerfile # The core Docker multi-stage build instructions.
├── setup.sh # The root orchestrator script (the main ENTRYPOINT).
└── scripts/
├── 10-fix-permission.sh # Fixes storage path permissions.
├── 20-prisma-migrate.sh # Runs Prisma migrations.
├── 30-revalidate.sh # Triggers Next.js revalidation in the background.
└── 99-entrypoint.sh # The final script that starts the Node.js process.
- Create a new shell script in the
scripts/directory. - Name it with a number reflecting its execution order (e.g.,
25-my-task.sh). - Write your task logic. If you need to run a command as the
nextjsuser, usesu-exec nextjs <your-command>. - Make the script executable (
chmod +x). The orchestrator will automatically pick it up.
- Implement a
HEALTHCHECKinstruction in the Dockerfile. - Add support for graceful shutdowns within the application process.
- Create more script examples for common use-cases.
Contributions are welcome! If you have suggestions or find a bug, please feel free to:
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
For bugs and support, please open an issue.
Q: Why does the revalidation script wait for 5 seconds?
A: This delay gives the Next.js server enough time to fully start up and be ready to accept HTTP requests. Without it, the curl command might fail because it tries to connect to a server that isn't running yet.
Q: Can I run custom commands before the application starts?
A: Yes! That's the primary benefit of this architecture. Simply create a new script in the scripts/ directory with the desired execution number, and it will run automatically.
This project is licensed under the MIT License. See the LICENSE file for details.
- gecut - GitHub Profile