Deployment Guide
This guide explains how to deploy SwallowKit applications to Azure.
Table of Contents
Prerequisites
- Azure account
- Azure CLI (
az) installed - GitHub account (for GitHub Actions)
- Azure DevOps account (for Azure Pipelines)
Quick Start
1. Initialize Project
npx swallowkit init my-app
cd my-appChoose CI/CD provider during initialization:
- GitHub Actions
- Azure Pipelines
2. Provision Azure Resources
npx swallowkit provision --resource-group my-app-rgThe command then prompts you to choose:
- Primary location for Functions and Cosmos DB
- Static Web App location
This creates using Bicep templates:
- Azure Static Web Apps
- Azure Functions (Flex Consumption)
- Azure Cosmos DB (the Free Tier or Serverless option selected during initialization)
- Managed Identity (secure service connections)
After provisioning completes, the terminal shows resource information followed by the CI/CD secrets/variables in this format:
📝 Next Steps:
1. Configure CI/CD secrets/variables:
[AZURE_STATIC_WEB_APPS_API_TOKEN]
<token-value>
[AZURE_FUNCTIONAPP_NAME]
<Function App name>
[AZURE_FUNCTIONAPP_PUBLISH_PROFILE]
<profile-xml>Important: Copy these values — you will need them in step 4. If the CLI cannot retrieve the token or publish profile automatically, it prints the
azcommand to run manually instead.
3. Push Code
Push your code to trigger the CI/CD workflow:
git add .
git commit -m "Initial deployment"
git push origin mainNote: This push will automatically trigger the CI/CD workflow, but it will fail because secrets are not registered yet. This is expected — proceed to the next step.
4. Cancel, Register Secrets, and Re-run
Step 4-1: Cancel the auto-triggered CI/CD run
The initial push triggers a CI/CD run that cannot succeed without secrets. Cancel it:
- GitHub Actions: Go to the Actions tab → click the running workflow → Cancel workflow
- Azure Pipelines: Go to Pipelines → click the running pipeline → Cancel
Step 4-2: Register the secrets / variables displayed by provision
For GitHub Actions
- Go to your GitHub repository → Settings → Secrets and variables → Actions
- Add the following secrets using the values displayed after provisioning:
AZURE_STATIC_WEB_APPS_API_TOKENAZURE_FUNCTIONAPP_NAMEAZURE_FUNCTIONAPP_PUBLISH_PROFILE
For Azure Pipelines
- Azure DevOps → Pipelines → Library → Variable groups
- Create group named
azure-deployment - Add the following variables using the values displayed after provisioning:
AZURE_STATIC_WEB_APPS_API_TOKENAZURE_FUNCTIONAPP_NAMEAZURE_FUNCTIONAPP_PUBLISH_PROFILE
Step 4-3: Manually re-run the CI/CD workflow
- GitHub Actions: Actions tab → select the failed workflow → Re-run all jobs
- Azure Pipelines: Pipelines → select the failed pipeline → Run pipeline
Generated Resources
Azure Static Web Apps
- Purpose: Host Next.js application
- Mode: Standalone (optimized bundle size)
- Features:
- Global CDN
- Automatic HTTPS
- Custom domain support
Azure Functions
- Plan: Flex Consumption
- Runtime: Selected during initialization (TypeScript/Node.js 22, C#/.NET Isolated 8.0, or Python 3.11)
- Features:
- HTTP triggers
- Cosmos DB bindings
- Zod schema validation
Azure Cosmos DB
- Mode: The Free Tier or Serverless option selected during initialization
- Features:
- Automatic scaling
- Global distribution
- RBAC access control
Managed Identity
- Type: System-assigned managed identity
- Purpose: Secure service-to-service authentication without connection strings
- Permissions: Read/write access to Cosmos DB
CI/CD Workflows
Generated Files
.github/workflows/ # For GitHub Actions
├── static-web-app.yml # SWA deployment
└── azure-functions.yml # Functions deployment
pipelines/ # For Azure Pipelines
├── static-web-app.yml
└── azure-functions.ymlWorkflow Behavior
Static Web Apps Workflow:
- Triggers: Push to
main, changes inapp/**,components/**,lib/** - Steps:
- Build Next.js in standalone mode
- Deploy to Azure Static Web Apps
- Create preview environment (for PRs)
Azure Functions Workflow:
- Triggers: Push to
main, changes infunctions/** - Steps:
- Install dependencies
- Build TypeScript
- Deploy to Azure Functions
Path-Based Triggers
For efficient deployments, only relevant workflows run based on changed files:
- Frontend changes (
app/,components/,lib/) → Deploy SWA only - Backend changes (
functions/) → Deploy Functions only - Both changed → Deploy both
Environment Variables
Local Development (.env.local)
# Cosmos DB Emulator
COSMOS_DB_ENDPOINT=https://localhost:8081/
COSMOS_DB_KEY=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==
# Azure Functions (local)
BACKEND_API_URL=http://localhost:7071Production (Azure)
# Azure Functions
BACKEND_API_URL=https://<function-app-name>.azurewebsites.net
# Cosmos DB (Managed Identity - no key needed)
COSMOS_DB_ENDPOINT=https://<cosmosdb-account-name>.documents.azure.com:443/Important: In production, COSMOS_DB_KEY is not needed. Managed Identity handles authentication automatically.
Setting Variables in Azure
Static Web Apps:
az staticwebapp appsettings set \
--name <swa-name> \
--setting-names \
BACKEND_API_URL=https://<function-name>.azurewebsites.net \
COSMOS_DB_ENDPOINT=https://<cosmosdb-name>.documents.azure.com:443/Azure Functions:
az functionapp config appsettings set \
--name <function-name> \
--resource-group my-app-rg \
--settings \
COSMOS_DB_ENDPOINT=https://<cosmosdb-name>.documents.azure.com:443/Customizing Infrastructure
Editing Bicep Files
infra/
├── main.bicep # Main orchestration
├── main.parameters.json # Parameters
└── modules/
├── staticwebapp.bicep # SWA resource
├── functions.bicep # Functions + Storage
└── cosmosdb.bicep # Cosmos DB + RBACApplying Changes
# After editing Bicep files
npx swallowkit provision --resource-group my-app-rgCommon Customizations
Change Cosmos DB to provisioned:
// infra/modules/cosmosdb.bicep
resource cosmosAccount 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' = {
properties: {
// serverless → provisioned
capabilities: []
}
}Troubleshooting
Deployment Fails
Symptom: CI/CD pipeline fails with errors
Solution:
- Check GitHub/Azure DevOps logs
- Verify secrets are correctly set
- Ensure Azure resources provisioned successfully
# Check resources
az resource list --resource-group my-app-rg --output tableCannot Connect to Functions
Symptom: BFF calls to Functions fail
Solution:
- Verify
BACKEND_API_URLis correctly set - Check CORS configuration
az functionapp cors show \
--name <function-name> \
--resource-group my-app-rg- Ensure Functions are running
az functionapp show \
--name <function-name> \
--resource-group my-app-rg \
--query "state" -o tsvCosmos DB Connection Error
Symptom: "Unauthorized" or connection errors
Solution:
- Verify Managed Identity is enabled
az functionapp identity show \
--name <function-name> \
--resource-group my-app-rg- Check RBAC role assignment
az cosmosdb sql role assignment list \
--account-name <cosmosdb-name> \
--resource-group my-app-rg- Verify endpoint URL is correct
Slow Builds
Symptom: Next.js build takes too long
Solution:
- Use
.nextcache
# .github/workflows/static-web-app.yml
- uses: actions/cache@v3
with:
path: .next/cache
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}- Ensure
standalonemode is enabled (automatic)
Next Steps
- CLI Reference - All commands
- Scaffold Guide - CRUD code generation
