Netlify generates unique URLs for each deployment, with special patterns for functions, forms, and identity. Understanding these helps with testing and integration.
Key Takeaways
- 1Every deploy gets a permalink at {deploy-id}--{site}.netlify.app
- 2Functions are available at /.netlify/functions/{name}
- 3Redirect rules in _redirects or netlify.toml
- 4Branch deploys use {branch}--{site}.netlify.app pattern
- 5Split testing assigns visitors to branches via cookie
Netlify's URL structure is designed around the concept of immutable deploys. Every push creates a new deployment with a unique URL, making it easy to test changes, share previews, and roll back if something goes wrong.
URL Types
Netlify generates several URL types for different purposes. Understanding these patterns helps you share the right links with your team and configure webhooks correctly.
| Type | Pattern | Example |
|---|---|---|
| Production | {site}.netlify.app | mysite.netlify.app |
| Deploy permalink | {deploy-id}--{site}.netlify.app | abc123--mysite.netlify.app |
| Deploy Preview (PR) | deploy-preview-{number}--{site}.netlify.app | deploy-preview-42--mysite.netlify.app |
| Branch deploy | {branch}--{site}.netlify.app | staging--mysite.netlify.app |
| Functions | /.netlify/functions/{name} | /.netlify/functions/hello |
| Custom domain | your-domain.com | www.example.com |
Functions use a special /.netlify/functions/ path prefix, while all other URLs follow the pattern of identifier, double-dash, and site name. This makes Netlify URLs easy to identify and parse.
Deployment URLs
Each deployment URL pattern serves a specific purpose. Deploy permalinks are immutable snapshots, branch deploys update with each push to that branch, and Deploy Previews (built from pull requests) make code review easier.
# Netlify deployment URL patterns
# Production (latest from production branch)
https://{site-name}.netlify.app
# Deploy permalink (immutable)
https://{deploy-id}--{site-name}.netlify.app
# Branch deploy
https://{branch-name}--{site-name}.netlify.app
# Pull request preview
https://deploy-preview-{pr-number}--{site-name}.netlify.app
# Examples
https://my-gatsby-site.netlify.app
https://6123abc456def--my-gatsby-site.netlify.app
https://staging--my-gatsby-site.netlify.app
https://deploy-preview-42--my-gatsby-site.netlify.app
# With custom subdomain
https://docs.myapp.com -> Branch: docs
https://preview.myapp.com -> Latest deploy previewThe content at a deploy permalink never changes—bookmarking that URL will always show that exact deployment. Branch deploy URLs update with each push, making them ideal for staging environments.
Function URLs
Netlify Functions are serverless functions. By default they are accessible at /.netlify/functions/ followed by the function name (matching the filename without extension).
// Netlify Functions are at /.netlify/functions/{name}
// netlify/functions/hello.js
exports.handler = async (event, context) => {
const url = new URL(event.rawUrl);
const name = url.searchParams.get('name') || 'World';
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ message: `Hello, ${name}!` })
};
};
// Accessed at:
// https://mysite.netlify.app/.netlify/functions/hello?name=John
// With path parameters (custom path via config)
// netlify/functions/users.mjs
export default async (request, context) => {
const { id } = context.params;
return Response.json({ userId: id });
};
export const config = { path: "/users/:id" };
// URL: /users/123
// Background functions (async)
// netlify/functions/process-background.js
// URL: /.netlify/functions/process-background
// Returns 202 Accepted immediatelyFunctions receive the full request URL in event.rawUrl, making it easy to parse query parameters. Background functions return immediately with a 202 status, running asynchronously for long-running tasks.
Redirect Rules
Netlify's redirect rules are powerful and flexible. You can define them in a _redirects file or netlify.toml. The syntax supports placeholders, conditions, and proxy behavior.
# _redirects file
# Basic redirect
/old-page /new-page 301
# Splat matching
/blog/* /posts/:splat 301
/docs/* https://docs.example.com/:splat 200
# Proxy (shadow)
/api/* https://api.example.com/:splat 200
# Query string handling
/search q=:query /results?query=:query 301
# Country-based redirect
/store/* /store/us/:splat 302 Country=us
/store/* /store/eu/:splat 302 Country=de,fr,nl
# Role-based access (JWT roles): admins get through, others go to /login
/admin/* /admin/:splat 200! Role=admin
/admin/* /login 401!
# SPA fallback
/* /index.html 200
# Force HTTPS
http://example.com/* https://example.com/:splat 301!The :splat placeholder captures everything after the asterisk. Status 200 creates a proxy (rewrite), while 301/302 creates visible redirects. The ! suffix forces the redirect even for existing files.
netlify.toml Configuration
For more complex configurations, use netlify.toml. This TOML file supports environment-specific settings, header configuration, and redirect rules with full syntax highlighting in your editor.
# netlify.toml
[build]
publish = "dist"
command = "npm run build"
# Redirects
[[redirects]]
from = "/api/*"
to = "https://api.example.com/:splat"
status = 200
force = true
[[redirects]]
from = "/old-path"
to = "/new-path"
status = 301
# Headers
[[headers]]
for = "/api/*"
[headers.values]
Access-Control-Allow-Origin = "*"
Cache-Control = "no-cache"
[[headers]]
for = "/static/*"
[headers.values]
Cache-Control = "public, max-age=31536000"
# Environment-specific variables
[context.production]
environment = { API_URL = "https://api.example.com" }
[context.deploy-preview]
environment = { API_URL = "https://staging-api.example.com" }
[context.branch-deploy]
environment = { API_URL = "https://dev-api.example.com" }The [context] blocks let you set different environment variables for production, preview, and branch deploys. This is useful for pointing to different API backends or enabling debug features.
Edge Functions
Edge Functions run at the CDN edge, closer to your users than regular serverless functions. They are ideal for URL-based routing, authentication, and personalization that needs to happen before the page loads.
// netlify/edge-functions/transform.js
export default async (request, context) => {
const url = new URL(request.url);
// URL-based routing
if (url.pathname.startsWith('/api/')) {
// Modify request headers
const modifiedRequest = new Request(request, {
headers: new Headers({
...Object.fromEntries(request.headers),
'X-Custom-Header': 'value'
})
});
return context.next(modifiedRequest);
}
// URL rewriting
if (url.pathname === '/pricing') {
const country = context.geo.country?.code || 'US';
url.pathname = `/pricing/${country.toLowerCase()}`;
return url; // returning a URL rewrites to it
}
// Redirect
if (url.pathname === '/dashboard' && !context.cookies.get('session')) {
return Response.redirect(new URL('/login', request.url));
}
return context.next();
};
export const config = {
path: ["/*"]
};Edge Functions can modify requests, add headers, rewrite URLs, or redirect users. The context object provides geolocation data and cookie access for personalization decisions.
Form Handling URLs
Netlify Forms captures form submissions without requiring a backend. Add the data-netlify="true" attribute to enable automatic form handling, with submissions stored in your Netlify dashboard.
<!-- Netlify Forms -->
<form name="contact" method="POST" data-netlify="true">
<input type="hidden" name="form-name" value="contact" />
<input type="text" name="name" />
<input type="email" name="email" />
<button type="submit">Submit</button>
</form>
<!-- Form posts to same URL by default -->
<!-- Or specify action -->
<form name="contact" action="/thank-you" method="POST" data-netlify="true">
...
</form>
<!-- AJAX form submission -->
<script>
fetch('/', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
'form-name': 'contact',
'name': 'John',
'email': 'john@example.com'
})
});
</script>
<!-- Form submission webhook: configured in the Netlify UI
(Forms > Submission notifications > Outgoing webhook),
not in netlify.toml -->For AJAX submissions, POST to the current page URL with the form-name field included. You can configure an outgoing webhook (in the Forms notification settings) to receive submissions in real-time for integration with other services.
Netlify API URLs
Netlify provides a comprehensive REST API for managing sites, deploys, forms, and functions programmatically. This is useful for building custom dashboards, deployment automation, or content management integrations.
// Netlify API
const baseUrl = 'https://api.netlify.com/api/v1';
// Common endpoints
const endpoints = {
// Sites
listSites: '/sites',
getSite: '/sites/{site_id}',
// Deploys
listDeploys: '/sites/{site_id}/deploys',
getDeploy: '/deploys/{deploy_id}',
createDeploy: '/sites/{site_id}/deploys',
// Forms
listForms: '/sites/{site_id}/forms',
listSubmissions: '/forms/{form_id}/submissions',
// Functions
listFunctions: '/sites/{site_id}/functions'
};
// Example: List deploys
const response = await fetch(`${baseUrl}/sites/${siteId}/deploys`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
API requests require a personal access token, which you can create in your Netlify account settings. The API follows REST conventions with clear endpoint patterns for each resource type.