Deploys applications to Netlify including functions, forms, redirects, and edge functions. Use when deploying static sites, JAMstack applications, or serverless functions.
Deploys applications to Netlify including functions, forms, redirects, and edge functions. Use when deploying static sites, JAMstack applications, or serverless functions.
/plugin marketplace add mgd34msu/goodvibes-plugin/plugin install goodvibes@goodvibes-marketThis skill inherits all available tools. When active, it can use any tool Claude has access to.
The modern web development platform for deploying and hosting websites.
Install CLI:
npm install -g netlify-cli
Login:
netlify login
Deploy:
netlify deploy
Deploy to production:
netlify deploy --prod
Visit https://app.netlify.com/drop and drag your build folder.
[build]
command = "npm run build"
publish = "dist"
functions = "netlify/functions"
[build.environment]
NODE_VERSION = "18"
# Production context
[context.production]
command = "npm run build:prod"
# Preview context (branch deploys)
[context.deploy-preview]
command = "npm run build:preview"
# Branch-specific
[context.staging]
command = "npm run build:staging"
# Dev settings
[dev]
command = "npm run dev"
port = 3000
targetPort = 5173
# Headers
[[headers]]
for = "/*"
[headers.values]
X-Frame-Options = "DENY"
X-XSS-Protection = "1; mode=block"
# Redirects
[[redirects]]
from = "/api/*"
to = "/.netlify/functions/:splat"
status = 200
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
Via Dashboard: Site settings > Environment variables > Add variable
Via CLI:
netlify env:set MY_VAR "value"
netlify env:list
netlify env:get MY_VAR
netlify env:unset MY_VAR
# netlify.toml
[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"
// In build process
const apiUrl = process.env.API_URL;
// In functions
export async function handler(event, context) {
const secret = process.env.API_SECRET;
}
// netlify/functions/hello.js
export async function handler(event, context) {
return {
statusCode: 200,
body: JSON.stringify({ message: 'Hello, World!' }),
};
}
// netlify/functions/users.ts
import type { Handler, HandlerEvent, HandlerContext } from '@netlify/functions';
interface User {
id: string;
name: string;
}
const handler: Handler = async (event: HandlerEvent, context: HandlerContext) => {
const { httpMethod, body, queryStringParameters } = event;
if (httpMethod === 'GET') {
const users: User[] = await getUsers();
return {
statusCode: 200,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(users),
};
}
if (httpMethod === 'POST') {
const data = JSON.parse(body || '{}');
const user = await createUser(data);
return {
statusCode: 201,
body: JSON.stringify(user),
};
}
return {
statusCode: 405,
body: 'Method Not Allowed',
};
};
export { handler };
// netlify/functions/scheduled.ts
import { schedule } from '@netlify/functions';
const handler = async () => {
console.log('Running scheduled task');
await runTask();
return { statusCode: 200 };
};
// Run every day at midnight
export const handler = schedule('0 0 * * *', handler);
// netlify/functions/background-task-background.js
// Suffix with -background for async processing
export async function handler(event, context) {
// Long-running task (up to 15 minutes)
await processLargeDataset();
return {
statusCode: 200,
};
}
// netlify/edge-functions/geo.ts
import type { Context } from '@netlify/edge-functions';
export default async (request: Request, context: Context) => {
const country = context.geo.country?.code ?? 'Unknown';
const city = context.geo.city ?? 'Unknown';
return new Response(
JSON.stringify({
message: `Hello from ${city}, ${country}!`,
}),
{
headers: { 'Content-Type': 'application/json' },
}
);
};
export const config = { path: '/api/geo' };
// netlify/edge-functions/auth.ts
import type { Context } from '@netlify/edge-functions';
export default async (request: Request, context: Context) => {
const token = request.headers.get('Authorization');
if (!token) {
return new Response('Unauthorized', { status: 401 });
}
// Validate token
const user = await validateToken(token);
if (!user) {
return new Response('Invalid token', { status: 403 });
}
// Continue to origin
return context.next();
};
export const config = { path: '/api/*' };
# netlify.toml
[[edge_functions]]
path = "/api/geo"
function = "geo"
[[edge_functions]]
path = "/api/*"
function = "auth"
# Simple redirect
/old-page /new-page 301
# Wildcard redirect
/blog/* /posts/:splat 301
# Rewrite (proxy)
/api/* /.netlify/functions/:splat 200
# SPA fallback
/* /index.html 200
# Conditional redirect
/country/* /us/:splat 200 Country=us
/country/* /uk/:splat 200 Country=gb
[[redirects]]
from = "/old"
to = "/new"
status = 301
[[redirects]]
from = "/api/*"
to = "https://api.example.com/:splat"
status = 200
force = true
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
conditions = { Role = ["admin"] }
<form name="contact" method="POST" data-netlify="true">
<input type="hidden" name="form-name" value="contact" />
<input type="text" name="name" required />
<input type="email" name="email" required />
<textarea name="message" required></textarea>
<button type="submit">Send</button>
</form>
function ContactForm() {
const [status, setStatus] = useState('');
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const form = e.currentTarget;
const formData = new FormData(form);
try {
await fetch('/', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams(formData as any).toString(),
});
setStatus('success');
} catch (error) {
setStatus('error');
}
};
return (
<form
name="contact"
method="POST"
data-netlify="true"
onSubmit={handleSubmit}
>
<input type="hidden" name="form-name" value="contact" />
<input type="text" name="name" required />
<input type="email" name="email" required />
<button type="submit">Send</button>
</form>
);
}
Configure in Dashboard: Forms > [Form Name] > Settings > Notifications
<!-- Add to HTML -->
<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
import netlifyIdentity from 'netlify-identity-widget';
netlifyIdentity.init();
// Open modal
netlifyIdentity.open();
// Login
netlifyIdentity.on('login', user => {
console.log('Logged in:', user);
});
// Logout
netlifyIdentity.on('logout', () => {
console.log('Logged out');
});
// Get current user
const user = netlifyIdentity.currentUser();
# Install
netlify lm:install
# Setup
netlify lm:setup
# Track files
git lfs track "*.jpg" "*.png" "*.gif"
// netlify/functions/upload.ts
import { getStore } from '@netlify/blobs';
export async function handler(event) {
const store = getStore('uploads');
// Store blob
await store.set('file-key', event.body, {
metadata: { contentType: 'image/png' },
});
// Get blob
const blob = await store.get('file-key');
// Delete blob
await store.delete('file-key');
return { statusCode: 200 };
}
# Start dev server
netlify dev
# Start with specific port
netlify dev --port 3000
# Link to site
netlify link
# Pull environment variables
netlify env:pull
| Mistake | Fix |
|---|---|
| Missing form-name input | Add hidden input with form name |
| Wrong publish directory | Check framework output folder |
| Functions not found | Use netlify/functions directory |
| Redirects not working | Check order (first match wins) |
| Build failures | Check build logs, Node version |
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.