Fixing Image Loading Issues on Netlify with netlify.toml Configuration
Table of Contents
- Introduction
- Understanding the Image Loading Issue
- What is netlify.toml?
- Why Image Optimization Fails on Netlify
- Solution: Disable Image Optimization
- Setting Up netlify.toml
- HTTP to HTTPS Redirect Configuration
- Complete netlify.toml Example
- Deploying to Netlify
- Conclusion
Introduction
Deploying a Next.js application to Netlify can be smooth, but you might encounter an unexpected issue: images fail to load in production even though they work perfectly locally and on Vercel. This typically happens because of how Next.js handles image optimization and how Netlify processes serverless functions. In this guide, we'll explore the root cause, understand the netlify.toml configuration file, and implement a complete solution including HTTPS redirects.
Understanding the Image Loading Issue
When you deploy your Next.js application to Netlify, you might notice images appearing broken or failing to load. Looking at the browser's Network tab, you'll see requests like:
/_next/image?url=https%3A%2F%2Fpicsum.photos%2Fseed%2Fimage%2F360%2F160&w=640&q=75
These requests return 404 errors or fail silently, even though the external image URL (like picsum.photos or unsplash.com) is valid and accessible.
What is netlify.toml?
netlify.toml is Netlify's configuration file that allows you to define build settings, environment variables, redirects, headers, functions, and other deployment behaviors. It's similar to other infrastructure-as-code files like docker-compose.yml or package.json.
Key purposes of netlify.toml:
- Define build commands and publish directory
- Configure environment variables
- Set up redirects and URL rewriting
- Add HTTP headers (security, caching, CORS)
- Configure serverless functions
- Define custom error pages
Unlike Vercel (which auto-detects Next.js configuration), Netlify requires explicit configuration for optimal Next.js support.
Why Image Optimization Fails on Netlify
Next.js Image Component includes built-in image optimization via the /_next/image API endpoint. This works by:
- Accepting an external image URL
- Downloading and optimizing the image on-the-fly
- Serving it in optimized formats (WebP, AVIF)
However:
- Vercel: Has native support for Next.js Image Optimization as a built-in service ✅
- Netlify: Does NOT have a built-in Image Optimization API. The
/_next/imageendpoint doesn't work because Netlify can't run the image processing logic ❌
When Netlify tries to handle the /_next/image request, it either:
- Returns a 404 (endpoint not found)
- Times out (no handler)
- Returns an error (serverless function failure)
Solution: Disable Image Optimization
The fix is to disable Next.js Image Optimization when building for Netlify. This tells Next.js to serve images directly from their source URLs without processing.
Step 1: Update next.config.js
Add environment variable detection and disable optimization:
const isNetlify = process.env.NETLIFY === 'true';
const nextConfig = {
env: {
// Your existing env vars
},
images: {
unoptimized: isNetlify, // Disable optimization on Netlify
domains: ['images.unsplash.com', 'picsum.photos', 'cdn.countryflags.com'],
},
// ... rest of config
};
module.exports = nextConfig;
Important: NETLIFY is a built-in environment variable that Netlify automatically sets to 'true' during builds. You don't need to manually configure it—it's provided for free by Netlify. This makes detection seamless:
- ✅ On Netlify builds:
process.env.NETLIFY === 'true'(automatic) - ✅ On Vercel/local:
process.env.NETLIFYis undefined → images use optimization - ✅ The same codebase works on both platforms without manual setup
Setting Up netlify.toml
Create a netlify.toml file in your project root. This tells Netlify how to build and serve your Next.js app.
Basic Configuration
[build]
command = "npm run build"
publish = ".next"
[functions]
external_node_modules = ["sharp"]
Explanation:
[build]: Defines how Netlify builds your projectcommand = "npm run build": Runs your Next.js buildpublish = ".next": Publishes the.nextdirectory (Next.js output)
[functions]: Serverless function configurationexternal_node_modules = ["sharp"]: Allows thesharplibrary (image processing) if needed
HTTP to HTTPS Redirect Configuration
Modern web standards require HTTPS. You can enforce this at the Netlify level using netlify.toml:
[[redirects]]
from = "http://*"
to = "https://:splat"
status = 301
force = true
How it works:
from = "http://*": Matches all HTTP URLs (wildcard*)to = "https://:splat": Redirects to HTTPS, preserving the path (:splatis Netlify's placeholder)status = 301: Permanent redirect (helps SEO)force = true: Forces redirect even if a file exists at that path
Example:
http://example.com/blog/post-1→https://example.com/blog/post-1(path preserved)
Complete netlify.toml Example
Here's a production-ready configuration with security headers:
# Netlify configuration for Next.js application
[build]
command = "npm run build"
publish = ".next"
[functions]
external_node_modules = ["sharp"]
# Redirect HTTP to HTTPS (permanent redirect)
[[redirects]]
from = "http://*"
to = "https://:splat"
status = 301
force = true
# Security headers
[[headers]]
for = "/*"
[headers.values]
# Enable HTTPS everywhere and HSTS (strict transport security)
Strict-Transport-Security = "max-age=31536000; includeSubDomains; preload"
# Prevent clickjacking attacks
X-Frame-Options = "DENY"
# Prevent MIME type sniffing
X-Content-Type-Options = "nosniff"
# Enable browser XSS protection
X-XSS-Protection = "1; mode=block"
# Cache static assets longer (optional)
[[headers]]
for = "/_next/static/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
# Custom error page (optional)
[[redirects]]
from = "/*"
to = "/404.html"
status = 404
Deploying to Netlify
Once you have netlify.toml ready, follow these steps:
Option 1: Using Netlify UI
- Push your code to GitHub
- Connect your repository to Netlify
- Deploy (that's it! Netlify automatically handles the rest)
✅ No manual environment variable setup needed. Netlify automatically sets NETLIFY=true during builds.
Option 2: Using Netlify CLI
# Install Netlify CLI
npm install -g netlify-cli
# Deploy
netlify deploy --prod
Netlify will automatically:
- Detect your
netlify.tomlconfiguration - Set the
NETLIFYenvironment variable to'true' - Build your Next.js app with image optimization disabled
Verify Configuration
After deployment:
- Check images load: Visit your site and verify all images render correctly
- Test HTTPS redirect: Visit
http://example.com→ should redirect tohttps://example.com - Inspect headers: Use browser DevTools → Network tab → check response headers for security directives
Conclusion
By understanding how Next.js Image Optimization works and Netlify's limitations, you can configure your application to work seamlessly across different platforms. The netlify.toml file is your gateway to fine-tuning deployment behavior, from disabling image optimization to enforcing HTTPS.
Key takeaways:
- ✅ Disable image optimization on Netlify using
unoptimized: isNetlifyinnext.config.js - ✅ Use
netlify.tomlto configure build settings, redirects, and security headers - ✅ Enforce HTTPS redirects for better security and SEO
- ✅ Test thoroughly before pushing to production
With this setup, your Next.js blog will work reliably on Netlify with all images loading correctly and your site protected by modern security standards.