Fix Build & Lint Issues in Docker: Deploying Next.js 15 with Supabase Safely
A Simple Web Developer & Designer
Deploying a modern Next.js app with Supabase can be tricky, especially when you want strict TypeScript and ESLint checks in your CI/CD pipeline. Here’s a guide based on real-world fixes that ensure production safety without skipping errors.
Common Problems
Docker builds fail due to ESLint / TypeScript errors
- Often developers skip build checks, hiding real issues.
Supabase middleware auth issues
Using session objects directly can be insecure.
Deprecated packages like
@supabase/auth-helpers-nextjscause runtime errors.
Static export errors
- Errors like
Objects are not valid as React childwhen rendering dynamic content.
- Errors like
Native module build errors
- Packages like
sharporbcryptfail on Alpine images.
- Packages like
How to Fix
1. Enforce ESLint & TypeScript in Docker
# Install dependencies
RUN pnpm install --frozen-lockfile
# Run lint & type checks before build
RUN pnpm run lint
RUN pnpm exec tsc --noEmit
# Build Next.js app
RUN pnpm run build
Benefit: CI/CD fails early if there are errors, preventing runtime bugs.
2. Use Node 20 Bullseye Slim for Docker
FROM node:20-bullseye-slim AS builder
- Ensures smooth builds for native modules like
sharpandesbuild.
3. Force dynamic pages to avoid static export errors
// next.config.js
const nextConfig = {
dynamicParams: true,
dynamicIO: true,
generateStaticParams: async () => [],
};
export default nextConfig;
- Prevents common errors when prerendering pages with dynamic data.
4. Use secure Supabase server-side auth
import { NextResponse } from "next/server";
import { createServerClient } from "@supabase/ssr";
export async function middleware(req) {
const res = NextResponse.next();
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{ cookies: { getAll: () => [], setAll: () => {} } }
);
const { data: { session } } = await supabase.auth.getSession();
const role = session?.user.user_metadata?.role || "user";
if (!session) return NextResponse.redirect("/login");
if (role !== "admin" && req.nextUrl.pathname.startsWith("/admin")) {
return NextResponse.redirect("/");
}
return res;
}
Benefit: Server-verified sessions and RBAC without insecure client hacks.
5. Clean Docker Production Image
- Prune dev dependencies:
RUN pnpm prune --prod
Copy
.next,public, andnode_modulesfrom builder to runner.Use non-root user for security.
6. Deploy to Serverless Platform (Cloud Run Example)
gcloud run deploy my-next-app \
--image <PROJECT-ID>/<REPO>/app:v1.0.0 \
--platform managed \
--allow-unauthenticated \
--port 3000 \
--set-env-vars NEXT_PUBLIC_SUPABASE_URL=...,NEXT_PUBLIC_SUPABASE_ANON_KEY=...
- Fully managed, scalable and HTTPS-ready deployment.
Key Takeaways
Do not skip TypeScript or ESLint checks — enforce them in Docker for safer production builds.
Node 20 Bullseye Slim ensures native modules compile correctly.
Supabase server-side auth avoids insecure session usage.
Dynamic pages in Docker prevent static export errors.
Clean production image improves CI/CD reliability and security.

