Skip to main content

Serverless Deployment

SQLPage can run on serverless platforms like AWS Lambda, enabling automatic scaling and pay-per-request pricing for your applications.

AWS Lambda Deployment

Overview

SQLPage includes a special Lambda runtime that allows it to handle HTTP requests through AWS Lambda and API Gateway. Benefits:
  • Zero infrastructure management
  • Automatic scaling from zero to thousands of requests
  • Pay only for actual usage
  • Built-in high availability
Trade-offs:
  • Cold start latency (1-3 seconds for first request)
  • 15-minute maximum execution time
  • Limited to 10GB memory and 512MB /tmp storage
  • Best for applications with intermittent traffic

Building for Lambda

SQLPage provides a pre-configured Dockerfile for Lambda:
# lambda.Dockerfile
FROM rust:1.91-alpine AS builder

# Install dependencies
RUN rustup component add clippy rustfmt
RUN apk add --no-cache musl-dev zip

WORKDIR /usr/src/sqlpage

# Build dependencies first (for caching)
RUN cargo init .
COPY Cargo.toml Cargo.lock ./
RUN cargo build --release

# Build SQLPage with Lambda support
COPY . .
RUN cargo build --release --features lambda-web

# Create deployment package
RUN mv target/release/sqlpage bootstrap && \
    strip --strip-all bootstrap && \
    zip -9 -r deploy.zip bootstrap index.sql

# Runtime image
FROM public.ecr.aws/lambda/provided:al2 AS runner
COPY --from=builder /usr/src/sqlpage/bootstrap /main
COPY --from=builder /usr/src/sqlpage/index.sql ./index.sql
ENTRYPOINT ["/main"]

Build the Lambda Function

# Clone SQLPage repository
git clone https://github.com/sqlpage/SQLPage.git
cd SQLPage

# Build Lambda deployment package
docker build -f lambda.Dockerfile -t sqlpage-lambda .

# Extract the deployment zip
docker create --name temp sqlpage-lambda
docker cp temp:/usr/src/sqlpage/deploy.zip ./deploy.zip
docker rm temp

Deploy to AWS Lambda

Using AWS Console

  1. Create Lambda Function:
    • Go to AWS Lambda Console
    • Click “Create function”
    • Choose “Container image”
    • Name: sqlpage-app
    • Container image URI: Upload your image to ECR first
  2. Configure Function:
    • Memory: 512 MB (adjust based on needs)
    • Timeout: 30 seconds (or higher)
    • Environment variables:
      • DATABASE_URL: Your database connection string
      • RUST_LOG: sqlpage=info
  3. Create API Gateway:
    • Add HTTP API trigger
    • Create new API
    • Security: Open (or configure authentication)

Using AWS CLI

# Create execution role
aws iam create-role --role-name sqlpage-lambda-role \
  --assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"},"Action":"sts:AssumeRole"}]}'

# Attach basic execution policy
aws iam attach-role-policy --role-name sqlpage-lambda-role \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

# Create function from zip
aws lambda create-function --function-name sqlpage-app \
  --runtime provided.al2 \
  --role arn:aws:iam::YOUR_ACCOUNT_ID:role/sqlpage-lambda-role \
  --handler not.used \
  --zip-file fileb://deploy.zip \
  --timeout 30 \
  --memory-size 512 \
  --environment Variables="{DATABASE_URL=sqlite:///tmp/sqlpage.db}"

# Create HTTP API
aws apigatewayv2 create-api --name sqlpage-api \
  --protocol-type HTTP \
  --target arn:aws:lambda:us-east-1:YOUR_ACCOUNT_ID:function:sqlpage-app

# Grant API Gateway permission to invoke Lambda
aws lambda add-permission --function-name sqlpage-app \
  --statement-id apigateway-invoke \
  --action lambda:InvokeFunction \
  --principal apigateway.amazonaws.com

Using SQLite with Lambda

For SQLite databases on Lambda, use the /tmp directory:
# Environment variable
DATABASE_URL=sqlite:///tmp/sqlpage.db?mode=rwc
Important limitations:
  • /tmp is ephemeral (cleared when function scales down)
  • Maximum 512 MB storage
  • Not suitable for persistent data
Solution: Use Lambda Layers or bootstrap script to copy database from S3:
-- init.sql: Run on cold start to restore database from S3
SELECT sqlpage.exec('aws', 's3', 'cp', 's3://my-bucket/sqlpage.db', '/tmp/sqlpage.db')
WHERE NOT EXISTS (SELECT 1 FROM sqlite_master);

Using Amazon RDS

For production Lambda deployments, use a managed database:
# PostgreSQL on RDS
DATABASE_URL=postgres://user:password@mydb.123456.us-east-1.rds.amazonaws.com:5432/sqlpage

# MySQL on RDS
DATABASE_URL=mysql://user:password@mydb.123456.us-east-1.rds.amazonaws.com:3306/sqlpage
Configuration tips:
  • Place Lambda in same VPC as RDS for low latency
  • Use RDS Proxy to pool database connections
  • Set appropriate connection pool size:
{
  "max_database_pool_connections": 5,
  "database_connection_idle_timeout_seconds": 10
}
Lambda functions reuse containers, so connection pooling is effective.

Deploying Your Application

# 1. Create your application structure
mkdir my-sqlpage-app
cd my-sqlpage-app

# 2. Add your SQL files
cat > index.sql << 'EOF'
SELECT 'text' AS component,
    'Hello from Lambda!' AS contents;

SELECT 'list' AS component;
SELECT 'Item ' || value AS title
FROM JSON_EACH('[1,2,3]');
EOF

# 3. Build custom Lambda image with your files
cat > Dockerfile << 'EOF'
FROM public.ecr.aws/lambda/provided:al2

# Copy pre-built SQLPage Lambda binary
COPY bootstrap /main

# Copy your application
COPY *.sql ./
COPY sqlpage/ ./sqlpage/

ENTRYPOINT ["/main"]
EOF

# 4. Build and push to ECR
aws ecr create-repository --repository-name sqlpage-app
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin YOUR_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com

docker build -t sqlpage-app .
docker tag sqlpage-app:latest YOUR_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/sqlpage-app:latest
docker push YOUR_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/sqlpage-app:latest

# 5. Update Lambda function
aws lambda update-function-code --function-name sqlpage-app \
  --image-uri YOUR_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/sqlpage-app:latest

Optimizing for Serverless

Reduce Cold Start Time

  1. Minimize dependencies:
    • Use SQLite for small apps
    • Remove unused SQLPage components
  2. Provisioned Concurrency:
    aws lambda put-provisioned-concurrency-config \
      --function-name sqlpage-app \
      --provisioned-concurrent-executions 2
    
    Keeps 2 warm instances ready (incurs hourly cost).
  3. Optimize connection pooling:
    {
      "max_database_pool_connections": 3,
      "database_connection_acquire_timeout_seconds": 5
    }
    

Minimize Response Size

{
  "compress_responses": true
}
Smaller responses = faster delivery = lower costs.

Cache Static Assets

Use API Gateway caching:
aws apigatewayv2 create-stage --api-id abc123 \
  --stage-name prod \
  --default-route-settings '{"ThrottlingBurstLimit":100,"ThrottlingRateLimit":50}'
Or CloudFront CDN in front of API Gateway.

Database Migration on Lambda

Run migrations on Lambda startup:
-- sqlpage/migrations/0001_init.sql
CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY,
    username TEXT UNIQUE NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
SQLPage automatically runs migrations from sqlpage/migrations/ on startup. For complex migrations, use a separate Lambda function or run locally before deployment.

Monitoring Lambda Functions

CloudWatch Logs

View logs in AWS Console or via CLI:
aws logs tail /aws/lambda/sqlpage-app --follow

Enable Detailed Logging

aws lambda update-function-configuration --function-name sqlpage-app \
  --environment Variables="{DATABASE_URL=...,RUST_LOG=sqlpage=debug}"

CloudWatch Metrics

Monitor:
  • Invocations
  • Duration
  • Errors
  • Throttles
  • Cold starts (via custom metrics)

X-Ray Tracing

Enable for detailed performance analysis:
aws lambda update-function-configuration --function-name sqlpage-app \
  --tracing-config Mode=Active

Cost Optimization

Lambda Pricing (us-east-1)

  • Requests: $0.20 per 1 million requests
  • Compute: $0.0000166667 per GB-second
Example:
  • 1 million requests/month
  • 512 MB memory
  • 500ms average duration
Cost calculation:
Requests: 1M * $0.20 / 1M = $0.20
Compute: 1M * 0.5s * 0.5GB * $0.0000166667 = $4.17
Total: ~$4.37/month
Vs. dedicated server: $5-20/month (but always running).

When Serverless Makes Sense

Good for:
  • Intermittent traffic (bursty or infrequent)
  • Development/staging environments
  • Internal tools with sporadic usage
  • Auto-scaling from zero
Not ideal for:
  • Consistent high traffic (dedicated server cheaper)
  • Real-time applications (cold start latency)
  • Large file processing (use ECS/EKS instead)

Alternative Serverless Platforms

Google Cloud Functions

Similar to AWS Lambda, supports custom runtimes:
gcloud functions deploy sqlpage \
  --runtime provided \
  --trigger-http \
  --allow-unauthenticated \
  --entry-point main

Azure Functions

Supports custom containers:
az functionapp create --resource-group myResourceGroup \
  --name sqlpage-app \
  --storage-account mystorageaccount \
  --plan myAppServicePlan \
  --deployment-container-image-name myregistry.azurecr.io/sqlpage:latest

Cloudflare Workers

Not directly compatible (Workers use V8 isolates, not containers). Consider:
  • Cloudflare Workers + SQLite with D1
  • Cloudflare Workers + external database via TCP

Vercel/Netlify

These platforms don’t support custom runtimes like SQLPage. Consider traditional deployment instead.

Hybrid Approach: Lambda + ECS

Pattern: Use Lambda for infrequent endpoints, ECS for core application.
  • Lambda: Admin panel, batch jobs, webhooks
  • ECS: Main user-facing application
  • Shared database (RDS)

Security Best Practices

Use AWS Secrets Manager

Store sensitive data securely:
# Store database password
aws secretsmanager create-secret --name sqlpage-db-password \
  --secret-string "my-secure-password"

# Grant Lambda permission to read secret
aws iam attach-role-policy --role-name sqlpage-lambda-role \
  --policy-arn arn:aws:iam::aws:policy/SecretsManagerReadWrite
Access in SQLPage:
SET password = sqlpage.fetch('https://secretsmanager.us-east-1.amazonaws.com/...');
Or use AWS SDK in environment bootstrap.

VPC Configuration

Place Lambda in VPC for secure database access:
aws lambda update-function-configuration --function-name sqlpage-app \
  --vpc-config SubnetIds=subnet-123,subnet-456,SecurityGroupIds=sg-789

IAM Least Privilege

Grant only necessary permissions:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "ec2:CreateNetworkInterface",
        "ec2:DescribeNetworkInterfaces",
        "ec2:DeleteNetworkInterface"
      ],
      "Resource": "*"
    }
  ]
}

Testing Lambda Functions Locally

AWS SAM CLI

# Install SAM CLI
pip install aws-sam-cli

# Create template.yaml
cat > template.yaml << 'EOF'
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
  SQLPageFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: .
      Handler: not.used
      Runtime: provided.al2
      Environment:
        Variables:
          DATABASE_URL: sqlite:///tmp/sqlpage.db
      Events:
        Api:
          Type: Api
          Properties:
            Path: /{proxy+}
            Method: ANY
EOF

# Test locally
sam build
sam local start-api
Access at http://localhost:3000.

Troubleshooting

Cold Start Too Slow

  • Enable provisioned concurrency
  • Reduce package size
  • Use smaller memory (paradoxically faster cold starts)

Database Connection Errors

  • Check VPC configuration
  • Verify security group rules
  • Ensure Lambda has internet access (NAT Gateway) if database is external
  • Check connection string format

Out of Memory

  • Increase Lambda memory allocation
  • Reduce database connection pool size
  • Optimize SQL queries to return less data

Timeout Errors

  • Increase function timeout (max 15 minutes)
  • Optimize slow SQL queries
  • Add database indexes

Resources

Build docs developers (and LLMs) love