Spaces:
Running
Server Features
This guide covers OSW Studio's advanced server features, available in Server Mode only.
Overview
Server Mode unlocks powerful backend capabilities for your published sites, including serverless API endpoints, database management, and secure secrets storage.
Key Features:
- Edge Functions - REST API endpoints with JavaScript runtime
- Database - Per-site SQLite with SQL editor and schema browser
- Server Functions - Reusable helper code for edge functions
- Scheduled Functions - Run edge functions on cron schedules
- Secrets - Encrypted storage for API keys and tokens
- Logs - Execution history and debugging
- AI Integration - AI awareness of server features via
/.server/folder
Prerequisites
- OSW Studio running in Server Mode
- A published site with
databaseEnabled: true - Admin access to the site
Accessing Server Settings
- Open the Admin Dashboard (
/admin) - Navigate to Sites and select your site
- Click the Server Settings button (server icon) next to Site Settings
- The server icon only appears for published sites with database enabled
- You can also access it via the "..." dropdown menu → "Server Settings"
The Server Settings modal contains seven tabs:
- Schema - Browse tables and columns
- SQL - Execute raw SQL queries
- Functions - Create and manage edge functions (HTTP endpoints)
- Helpers - Create and manage server functions (reusable code)
- Secrets - Store encrypted API keys and tokens
- Schedules - Create and manage scheduled functions (cron jobs)
- Logs - View function execution history
Edge Functions
Creating a Function
Go to Server Settings → Functions
Click New Function
Configure:
- Name: Lowercase letters, numbers, and hyphens (e.g.,
get-users) - HTTP Method: GET, POST, PUT, DELETE, or ANY
- Description: Optional description
- Timeout: 1-30 seconds (default: 5s)
- Code: JavaScript function body
- Name: Lowercase letters, numbers, and hyphens (e.g.,
Click Create Function
Function URL
Each function is accessible at:
https://your-server.com/api/sites/{siteId}/functions/{function-name}
For example:
https://oswstudio.com/api/sites/abc123/functions/get-products
Calling Edge Functions from Published Sites
Published sites automatically route edge function calls! Your frontend JavaScript can call functions using simple paths:
// In your published site's JavaScript
const response = await fetch('/submit-contact', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'John', email: 'john@example.com' })
});
const result = await response.json();
This works because OSW Studio injects a lightweight interceptor script (~1.5KB) into published HTML files that:
- Detects requests that look like edge function calls (paths without file extensions)
- Routes them to
/api/sites/{siteId}/functions/{path} - Works with
fetch(),XMLHttpRequest, and form submissions
Form submissions are also intercepted:
<form action="/submit-contact" method="POST">
<input name="email" type="email" required>
<button type="submit">Subscribe</button>
</form>
The form data is automatically converted to JSON and sent to your edge function.
Custom event handling:
// Listen for edge function responses
document.addEventListener('edge-function-response', (e) => {
console.log('Result:', e.detail.result);
});
document.addEventListener('edge-function-error', (e) => {
console.error('Error:', e.detail.error);
});
Available APIs
Your function code has access to these global objects:
request Object
request.method // HTTP method (GET, POST, etc.)
request.body // Parsed JSON body (POST/PUT/PATCH)
request.query // Query string parameters
request.headers // Request headers
request.path // URL path after function name
request.params // Path parameters (if any)
db Object (Database)
// Execute SELECT queries
const users = db.query('SELECT * FROM users WHERE active = ?', [true]);
const user = db.all('SELECT * FROM users LIMIT 10'); // alias for query
// Execute INSERT/UPDATE/DELETE
const result = db.run('INSERT INTO users (name, email) VALUES (?, ?)', ['John', 'john@example.com']);
// result = { changes: 1 }
Response Object
// Return JSON
Response.json({ users: [...] });
Response.json({ error: 'Not found' }, 404);
// Return plain text
Response.text('Hello World');
Response.text('Created', 201);
// Return error
Response.error('Something went wrong', 500);
Response.error('Unauthorized', 401);
fetch Function
// Make external HTTP requests
const response = await fetch('https://api.example.com/data');
const data = await response.json();
Response.json(data);
// With options
const res = await fetch('https://api.example.com/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: { name: 'John', email: 'john@example.com' }
});
Security Limits:
- Max 10 requests per function execution
- 10 second timeout per request
- 5MB max response body
- Only
http://andhttps://protocols allowed - Private IPs blocked in production (localhost, 10.x.x.x, 172.16-31.x.x, 192.168.x.x, 169.254.x.x)
- Development mode allows local requests for testing
atob / btoa Functions
// Base64 encode
const encoded = btoa('Hello World'); // "SGVsbG8gV29ybGQ="
// Base64 decode
const decoded = atob('SGVsbG8gV29ybGQ='); // "Hello World"
server Object (Helper Functions)
// Call server functions (helpers) defined in the Helpers tab
const auth = server.validateAuth(request.headers['x-api-key']);
const formatted = server.formatPrice(29.99, 'USD');
const user = server.getUserById(123);
See Server Functions (Helpers) for more details.
secrets Object (Encrypted Secrets)
// Get secret value by name
const apiKey = secrets.get('STRIPE_API_KEY');
if (!apiKey) {
Response.error('Stripe not configured', 500);
return;
}
// Check if secret exists
if (secrets.has('SENDGRID_KEY')) {
// Use SendGrid
}
// List all available secret names
const allSecrets = secrets.list(); // ['STRIPE_API_KEY', 'SENDGRID_KEY', ...]
See Secrets for more details.
Example Functions
List Items (GET)
// GET /api/sites/{siteId}/functions/list-items
const items = db.query('SELECT * FROM items ORDER BY created_at DESC LIMIT 20');
Response.json({ items });
Create Item (POST)
// POST /api/sites/{siteId}/functions/create-item
if (!request.body.name) {
Response.error('Name is required', 400);
return;
}
const result = db.run(
'INSERT INTO items (name, description) VALUES (?, ?)',
[request.body.name, request.body.description || '']
);
Response.json({
id: result.lastInsertRowid,
message: 'Item created'
}, 201);
Get Item by ID (GET with path)
// GET /api/sites/{siteId}/functions/get-item/123
const id = request.path.split('/')[1];
if (!id) {
Response.error('ID required', 400);
return;
}
const item = db.query('SELECT * FROM items WHERE id = ?', [id]);
if (item.length === 0) {
Response.error('Item not found', 404);
return;
}
Response.json(item[0]);
External API Proxy
// GET /api/sites/{siteId}/functions/weather?city=London
const city = request.query.city || 'New York';
const apiKey = secrets.get('WEATHER_API_KEY');
if (!apiKey) {
Response.error('Weather API not configured', 500);
return;
}
const res = await fetch(
`https://api.weatherapi.com/v1/current.json?key=${apiKey}&q=${city}`
);
const data = await res.json();
Response.json({
city: data.location.name,
temp: data.current.temp_c,
condition: data.current.condition.text
});
Security Considerations
Sandboxed Execution
- Functions run in a QuickJS WebAssembly sandbox - a completely separate JavaScript engine
- True isolation via WASM boundary: no shared memory or access to Node.js internals
- Memory limits enforced by WASM (64MB default)
- Execution time limits with interrupt handler (configurable 1-30 seconds)
- Allowed globals:
JSON,Date,Math,Array,Object,String,Number,Boolean,RegExp,Error,Map,Set,Promise,Symbol,console - Network:
fetch(with security limits - see above) - Utility functions:
parseInt,parseFloat,isNaN,isFinite,encodeURIComponent,decodeURIComponent,encodeURI,decodeURI - Base64:
atob(decode),btoa(encode) - No access to:
require,process,__dirname,Buffer, file system setTimeout/setIntervaldisabled (prevents runaway execution)
Database Protection
System tables are protected and cannot be accessed:
site_infofilesfile_tree_nodespageviewsinteractionssessionsedge_functionsfunction_logsserver_functionssecrets
Only user-created tables are accessible via the db API.
Query Limits
- Maximum 100 database queries per function execution
- Timeout enforced (1-30 seconds, configurable)
- SQL keywords validated to prevent dangerous operations
Managing Functions
Enable/Disable
Click the dropdown menu on a function card and select Enable or Disable. Disabled functions return 404.
Edit
Click Edit in the dropdown to modify the function code, method, or timeout.
Delete
Click Delete in the dropdown. This cannot be undone.
Copy URL
Click Copy URL below the function card to copy the public endpoint URL.
Server Functions (Helpers)
Server functions are reusable JavaScript helpers that can be called from your edge functions via the server object. They enable code reuse across multiple edge functions.
Creating a Server Function
- Go to Server Settings → Helpers
- Click New Helper
- Configure:
- Name: Valid JavaScript identifier (camelCase or snake_case, e.g.,
validateAuth,format_price) - Description: Optional description
- Code: JavaScript function body
- Name: Valid JavaScript identifier (camelCase or snake_case, e.g.,
- Click Create Function
How Server Functions Work
Server functions receive arguments via an args array and have access to db, fetch, and console. They return a value that is passed back to the calling edge function.
// Server function "validateAuth"
const [apiKey] = args;
if (!apiKey) {
return { valid: false, error: 'No API key provided' };
}
const users = db.query('SELECT * FROM users WHERE api_key = ?', [apiKey]);
if (users.length === 0) {
return { valid: false, error: 'Invalid API key' };
}
return { valid: true, user: users[0] };
Calling from Edge Functions
Server functions are available on the server object. Pass arguments as regular function parameters:
// Edge function code
const auth = server.validateAuth(request.headers['x-api-key']);
if (!auth.valid) {
Response.error(auth.error, 401);
return;
}
// User is authenticated
const products = db.query(
'SELECT * FROM products WHERE user_id = ?',
[auth.user.id]
);
Response.json({ products });
Available APIs in Server Functions
| API | Description |
|---|---|
args |
Array of arguments passed from edge function |
db.query() |
Execute SELECT query |
db.run() |
Execute INSERT/UPDATE/DELETE |
db.all() |
Alias for query |
fetch() |
Make external HTTP requests |
console.log() |
Log messages (visible in function logs) |
Example Server Functions
Validate API Key
// Name: validateAuth
const [apiKey] = args;
if (!apiKey) return { valid: false };
const users = db.query('SELECT id, name, role FROM users WHERE api_key = ?', [apiKey]);
return users.length > 0 ? { valid: true, user: users[0] } : { valid: false };
Format Price
// Name: formatPrice
const [amount, currency = 'USD'] = args;
const symbols = { USD: '$', EUR: '€', GBP: '£', JPY: '¥' };
const symbol = symbols[currency] || currency + ' ';
return symbol + amount.toFixed(2);
Get User by ID
// Name: getUserById
const [id] = args;
if (!id) return null;
const users = db.query('SELECT * FROM users WHERE id = ?', [id]);
return users.length > 0 ? users[0] : null;
Check Permission
// Name: hasPermission
const [userId, permission] = args;
if (!userId || !permission) return false;
const perms = db.query(
'SELECT 1 FROM user_permissions WHERE user_id = ? AND permission = ?',
[userId, permission]
);
return perms.length > 0;
Security Notes
- Server functions run in the same QuickJS WASM context as the parent edge function
- They share the total execution timeout (not additive)
- Recursive calls are possible but limited by timeout
- The
server_functionstable is protected and cannot be queried - Only enabled server functions are available to edge functions
Managing Server Functions
- Enable/Disable: Toggle from the dropdown menu. Disabled functions are not available to edge functions.
- Edit: Click Edit to modify the code or description
- Delete: Click Delete to remove (cannot be undone)
Secrets
Secrets provide secure, encrypted storage for sensitive values like API keys, tokens, and passwords. Edge functions can access secrets via the secrets object without exposing the actual values in your code.
Prerequisites
Before using secrets, you must set the SECRETS_ENCRYPTION_KEY environment variable:
# Generate a secure 256-bit key
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
# Add to your environment
export SECRETS_ENCRYPTION_KEY="your-generated-key-here"
Creating a Secret
- Go to Server Settings → Secrets
- Click New Secret
- Configure:
- Name: SCREAMING_SNAKE_CASE (e.g.,
STRIPE_API_KEY,SENDGRID_TOKEN) - Value: The secret value (will be encrypted)
- Description: Optional description
- Name: SCREAMING_SNAKE_CASE (e.g.,
- Click Create Secret
Using Secrets in Edge Functions
The secrets object is available in all edge functions:
// Get a secret value
const apiKey = secrets.get('STRIPE_API_KEY');
// Check if a secret exists
if (secrets.has('STRIPE_API_KEY')) {
// Use the secret
}
// List all available secret names (not values)
const names = secrets.list(); // ['STRIPE_API_KEY', 'SENDGRID_TOKEN', ...]
Example: Stripe API Integration
// POST /api/sites/{siteId}/functions/create-charge
const stripeKey = secrets.get('STRIPE_API_KEY');
if (!stripeKey) {
Response.error('Stripe not configured', 500);
return;
}
const { amount, currency, source } = request.body;
if (!amount || !source) {
Response.error('Amount and source are required', 400);
return;
}
const res = await fetch('https://api.stripe.com/v1/charges', {
method: 'POST',
headers: {
'Authorization': `Bearer ${stripeKey}`,
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
amount: String(amount),
currency: currency || 'usd',
source,
}),
});
const charge = await res.json();
Response.json({ charge });
Secrets API Reference
| Method | Description |
|---|---|
secrets.get(name) |
Get secret value, or null if not found |
secrets.has(name) |
Check if secret exists (returns boolean) |
secrets.list() |
Get array of all secret names (not values) |
Security Notes
- Encryption: Secrets are encrypted using AES-256-GCM with unique IVs per secret
- Never logged: Secret values are never written to logs or exposed in API responses
- Admin-only: Only authenticated admins can create, view (metadata only), or delete secrets
- Protected table: The
secretstable cannot be queried directly from edge functions - Key management: The master encryption key must be stored securely as an environment variable
Managing Secrets
- Edit: Click Edit in the dropdown to update the value or description (name cannot be changed)
- Delete: Click Delete to permanently remove (cannot be undone)
- No value display: Secret values are never displayed after creation for security
Scheduled Functions (Cron Jobs)
Scheduled functions run edge functions automatically on a cron schedule. Use them for periodic tasks like database cleanup, report generation, cache warming, or external API syncing.
Creating a Scheduled Function
- Go to Server Settings → Schedules
- Click New Schedule
- Configure:
- Name: Lowercase letters, numbers, and hyphens (e.g.,
daily-cleanup) - Edge Function: Select which edge function to invoke
- Cron Expression: Standard 5-field cron syntax (e.g.,
0 8 * * *) - Timezone: IANA timezone (default:
UTC) - Description: Optional description
- Config: Optional JSON object passed as the request body
- Name: Lowercase letters, numbers, and hyphens (e.g.,
- Click Create Schedule
How It Works
When a scheduled function fires:
- The cron scheduler triggers at the specified time
- The linked edge function is invoked with the
configobject asrequest.body - The execution result (success/error) and duration are recorded
- The next run time is calculated from the cron expression
The edge function runs in the same QuickJS sandbox as HTTP-triggered invocations, with full access to db, fetch, secrets, server, and console.
Cron Expression Reference
Cron expressions use 5 fields: minute hour day-of-month month day-of-week
Minimum interval: 5 minutes. Expressions that resolve to intervals shorter than 5 minutes will be rejected.
| Expression | Description |
|---|---|
*/5 * * * * |
Every 5 minutes |
0 * * * * |
Every hour (at minute 0) |
0 8 * * * |
Daily at 8:00 AM |
0 0 * * * |
Daily at midnight |
30 9 * * 1-5 |
Weekdays at 9:30 AM |
0 0 * * 1 |
Every Monday at midnight |
0 0 1 * * |
First of every month at midnight |
0 0 1 1 * |
January 1st at midnight (yearly) |
Field ranges:
- Minute: 0-59
- Hour: 0-23
- Day of month: 1-31
- Month: 1-12
- Day of week: 0-7 (0 and 7 = Sunday)
Example Scheduled Functions
Daily Database Cleanup
Clean up old records every day at 3:00 AM UTC:
- Edge Function (
cleanup):
const daysToKeep = request.body.daysToKeep || 30;
const cutoff = new Date(Date.now() - daysToKeep * 86400000).toISOString();
const result = db.run('DELETE FROM logs WHERE created_at < ?', [cutoff]);
Response.json({ deleted: result.changes, cutoff });
- Schedule config:
- Cron:
0 3 * * * - Config:
{ "daysToKeep": 30 }
- Cron:
Hourly Stats Aggregation
Aggregate analytics data every hour:
- Edge Function (
aggregate-stats):
const hourAgo = new Date(Date.now() - 3600000).toISOString();
const stats = db.query('SELECT COUNT(*) as views FROM pageviews WHERE timestamp > ?', [hourAgo]);
db.run('INSERT INTO hourly_stats (hour, views) VALUES (?, ?)',
[new Date().toISOString().slice(0, 13), stats[0].views]);
Response.json({ aggregated: true, views: stats[0].views });
- Schedule config:
- Cron:
0 * * * * - Config:
{}
- Cron:
Weekly Report Email
Send a weekly summary every Monday at 9:00 AM:
- Edge Function (
send-weekly-report):
const apiKey = secrets.get('SENDGRID_KEY');
if (!apiKey) { Response.error('Email not configured', 500); return; }
const stats = db.query('SELECT COUNT(*) as total FROM orders WHERE created_at > datetime("now", "-7 days")');
const res = await fetch('https://api.sendgrid.com/v3/mail/send', {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + apiKey, 'Content-Type': 'application/json' },
body: JSON.stringify({
personalizations: [{ to: [{ email: request.body.recipient }] }],
from: { email: 'reports@example.com' },
subject: 'Weekly Report',
content: [{ type: 'text/plain', value: 'Orders this week: ' + stats[0].total }]
})
});
Response.json({ sent: res.ok });
- Schedule config:
- Cron:
0 9 * * 1 - Timezone:
America/New_York - Config:
{ "recipient": "admin@example.com" }
- Cron:
Managing Scheduled Functions
- Enable/Disable: Toggle from the dropdown menu. Disabled schedules won't fire.
- Edit: Click Edit to modify the cron expression, linked function, timezone, or config.
- Delete: Click Delete to remove (cannot be undone).
- Status tracking: Each schedule card shows the next run time, last run status (success/error), and last run time.
SQL Editor
The SQL Editor allows direct SQL query execution against your site's database.
Executing Queries
- Go to Server Settings → SQL
- Type your SQL query in the editor
- Click Execute or press
Ctrl/Cmd + Enter - View results in the table below
Query History
The editor maintains a history of your last 20 queries (stored in browser localStorage).
Click History to view and re-run previous queries.
Supported Operations
-- SELECT queries
SELECT * FROM products WHERE price > 100;
SELECT COUNT(*) FROM orders;
-- INSERT
INSERT INTO products (name, price) VALUES ('Widget', 29.99);
-- UPDATE
UPDATE products SET price = 24.99 WHERE id = 1;
-- DELETE
DELETE FROM products WHERE discontinued = 1;
-- CREATE TABLE
CREATE TABLE products (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
price REAL DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- ALTER TABLE
ALTER TABLE products ADD COLUMN stock INTEGER DEFAULT 0;
-- DROP TABLE (use with caution!)
DROP TABLE old_products;
Query Safety
- System tables are accessible (read-only for some operations)
- All queries are executed with full permissions - use caution!
- No automatic transaction management - consider wrapping related operations
Schema Viewer
The Schema Viewer displays your database structure.
Viewing Tables
- Go to Server Settings → Schema
- Click on a table name to expand and view columns
- Each column shows: name, type, nullable, default value, primary key status
System Tables
Toggle Show System Tables to view OSW Studio's internal tables:
site_info- Site metadatafiles- File contentsfile_tree_nodes- File tree structurepageviews/interactions/sessions- Analytics dataedge_functions- Function definitionsfunction_logs- Execution logs
System tables are marked with a "(system)" label.
Execution Logs
View function execution history in the Logs tab.
Log Information
Each log entry shows:
- Status: Success (2xx), redirect (3xx), or error (4xx/5xx)
- Function: Function name
- Method: HTTP method used
- Path: Request path
- Duration: Execution time in milliseconds
- Time: Timestamp
Managing Logs
- Click Refresh to load latest logs
- Click Clear to delete all logs (cannot be undone)
- Logs are limited to the most recent 200 entries
Best Practices
Function Design
- Keep functions focused - One function per operation
- Validate input - Check
request.bodyandrequest.querybefore use - Handle errors - Return appropriate HTTP status codes
- Use meaningful names -
create-ordernotfunc1
Database Usage
Use parameterized queries - Prevents SQL injection
// Good db.query('SELECT * FROM users WHERE id = ?', [userId]); // Bad - SQL injection risk! db.query(`SELECT * FROM users WHERE id = ${userId}`);Create indexes for frequently queried columns:
CREATE INDEX idx_orders_user_id ON orders(user_id);Limit result sets to avoid memory issues:
db.query('SELECT * FROM products LIMIT 100');
Performance
- Set appropriate timeouts - Don't use 30s if 5s is sufficient
- Minimize external requests - Each
fetch()adds latency - Cache when possible - Store API responses in your database
Troubleshooting
Function Returns 404
- Check that the function is enabled
- Verify the function name in the URL is correct
- Ensure the site is published and has database enabled
Function Returns 500
- Check the Logs tab for error details
- Verify your SQL queries are valid
- Ensure external APIs are responding
Query Execution Failed
- Check SQL syntax
- Verify table and column names
- Look for constraint violations (unique, foreign key)
Cannot Access Table
- System tables are protected in edge functions
- Use the SQL Editor for system table access
API Reference
Public Endpoints
| Method | URL | Description |
|---|---|---|
| * | /api/sites/{siteId}/functions/{name} |
Invoke edge function |
| * | /api/sites/{siteId}/functions/{name}/* |
Invoke with path params |
Admin Endpoints (Requires Authentication)
| Method | URL | Description |
|---|---|---|
| GET | /api/admin/sites/{siteId}/functions |
List edge functions |
| POST | /api/admin/sites/{siteId}/functions |
Create edge function |
| GET | /api/admin/sites/{siteId}/functions/{id} |
Get edge function |
| PUT | /api/admin/sites/{siteId}/functions/{id} |
Update edge function |
| DELETE | /api/admin/sites/{siteId}/functions/{id} |
Delete edge function |
| GET | /api/admin/sites/{siteId}/server-functions |
List server functions |
| POST | /api/admin/sites/{siteId}/server-functions |
Create server function |
| GET | /api/admin/sites/{siteId}/server-functions/{id} |
Get server function |
| PUT | /api/admin/sites/{siteId}/server-functions/{id} |
Update server function |
| DELETE | /api/admin/sites/{siteId}/server-functions/{id} |
Delete server function |
| GET | /api/admin/sites/{siteId}/scheduled-functions |
List scheduled functions |
| POST | /api/admin/sites/{siteId}/scheduled-functions |
Create scheduled function |
| GET | /api/admin/sites/{siteId}/scheduled-functions/{id} |
Get scheduled function |
| PUT | /api/admin/sites/{siteId}/scheduled-functions/{id} |
Update scheduled function |
| DELETE | /api/admin/sites/{siteId}/scheduled-functions/{id} |
Delete scheduled function |
| GET | /api/admin/sites/{siteId}/secrets |
List secrets (metadata only) |
| POST | /api/admin/sites/{siteId}/secrets |
Create secret |
| GET | /api/admin/sites/{siteId}/secrets/{id} |
Get secret (metadata only) |
| PUT | /api/admin/sites/{siteId}/secrets/{id} |
Update secret |
| DELETE | /api/admin/sites/{siteId}/secrets/{id} |
Delete secret |
| GET | /api/admin/sites/{siteId}/database/schema |
Get schema |
| POST | /api/admin/sites/{siteId}/database/query |
Execute SQL |
| GET | /api/admin/sites/{siteId}/database/logs |
Get logs |
| DELETE | /api/admin/sites/{siteId}/database/logs |
Clear logs |
AI Integration
OSW Studio's AI assistant can understand and work with your server features when you select a site in the workspace.
How It Works
- Select a Site - Use the site selector dropdown in the workspace header
- Server Context Loaded - OSW Studio fetches the site's server features
- AI Awareness - The AI receives information about available:
- Edge functions (endpoints, methods)
- Database schema (tables, columns)
- Server functions (helpers)
- Scheduled functions (cron schedules)
- Secrets (names only, not values)
The /.server/ Folder
When a site is selected, a hidden /.server/ folder appears in the file explorer containing:
| Folder | Contents |
|---|---|
edge-functions/*.json |
Edge function endpoints |
server-functions/*.json |
Helper functions |
scheduled-functions/*.json |
Cron schedules |
secrets/*.json |
Secret names (not values) |
db/schema.sql |
Database schema |
These files are read-only and transient - they reflect the current site's state but are not saved with the project.
Using AI with Server Features
Example prompts:
What tables are in the database?
Create an edge function to list all products
I need an endpoint that validates API keys using the STRIPE_KEY secret
Create a scheduled function to clean up old records every night
Help me design a schema for a blog with posts and comments
The AI can:
- Read and explain your current schema
- Suggest edge function implementations
- Reference available secrets by name
- Help design database structures
- Debug function issues
Viewing Hidden Files
To see the /.server/ folder:
- Right-click in the File Explorer
- Select Show Hidden Files
- Look for the folder with the orange server icon
See also: Server Mode → Server Context Integration