Skip to content

URL Patterns Reference

Complete specification for Airbase application URLs

This document provides the authoritative reference for URL patterns used in Airbase, including environment-specific URLs, custom domains, and routing behavior.


Overview

Every deployed application in Airbase gets a unique URL based on its project handle and environment. URLs follow a predictable pattern that ensures no conflicts between applications.

Key concepts: - Automatic URL generation: Based on project handle and environment - Environment isolation: Each environment gets its own subdomain - HTTPS by default: All URLs use TLS encryption - Internal routing: Ingress controller routes traffic to containers


URL Structure

Standard URL Format

Pattern:

https://{environment}--{project-name}.app.{cluster-domain}

Components: - {environment}: Environment name (staging, production, or custom) - {project-name}: Project name from project handle (namespace/name) - {cluster-domain}: Airbase cluster domain

Examples:

# Staging environment
https://staging--myapp.app.tc1.airbase.sg

# Production environment (no environment prefix)
https://myapp.app.tc1.airbase.sg

# Custom environment
https://dev--myapp.app.tc1.airbase.sg


Environment-Specific URLs

Production Environment

Format: No environment prefix (clean URL)

Pattern:

https://{project-name}.app.{cluster-domain}

Example:

# Project handle: myteam/myapp
# Production URL:
https://myapp.app.tc1.airbase.sg

Notes: - Production gets the "clean" URL without environment prefix - Default environment when deploying with airbase container deploy - Most user-facing applications use this URL


Staging Environment

Format: With staging-- prefix

Pattern:

https://staging--{project-name}.app.{cluster-domain}

Example:

# Project handle: myteam/myapp
# Staging URL:
https://staging--myapp.app.tc1.airbase.sg

Notes: - Used for pre-production testing - Deploy with airbase container deploy --yes staging - Isolated from production environment


Custom Environments

Format: With custom name prefix

Pattern:

https://{custom-name}--{project-name}.app.{cluster-domain}

Examples:

# Development environment
https://dev--myapp.app.tc1.airbase.sg

# UAT environment
https://uat--myapp.app.tc1.airbase.sg

# Feature branch
https://feature-auth--myapp.app.tc1.airbase.sg

Deploy command:

airbase container deploy --yes dev
airbase container deploy --yes uat
airbase container deploy --yes feature-auth

Notes: - Any alphanumeric name is allowed for environments - Use lowercase with hyphens (no underscores or spaces) - Each environment is fully isolated


URL Components Reference

Project Name

Derived from: Project handle in airbase.json

Format: namespace/project-name

URL uses: Only the project-name part (after /)

Example:

{
  "framework": "container",
  "handle": "analytics/dashboard",
  "port": 3000,
  "instanceType": "nano"
}

Results in:

Production:  https://dashboard.app.tc1.airbase.sg
Staging:     https://staging--dashboard.app.tc1.airbase.sg


Environment Name

Valid characters: - Lowercase letters: a-z - Numbers: 0-9 - Hyphens: -

Restrictions: - Cannot start or end with hyphen - Cannot contain spaces or underscores - Maximum length: 63 characters

Valid examples:

staging
production
dev
feature-123
hotfix-auth
release-2024-03

Invalid examples:

Staging          # Uppercase not allowed
_dev             # Underscore not allowed
dev_feature      # Underscore not allowed
feature branch   # Spaces not allowed
-feature         # Cannot start with hyphen
feature-         # Cannot end with hyphen


Cluster Domain

Format: tc1.airbase.sg, tc2.airbase.sg, etc.

Managed by: Airbase platform

Cannot be changed: Set at cluster level

Different clusters:

# Training Cluster 1
https://myapp.app.tc1.airbase.sg

# Training Cluster 2
https://myapp.app.tc2.airbase.sg

Notes: - Each cluster has its own domain - Projects deployed to different clusters get different URLs - Check with platform team for your cluster assignment


URL Examples by Scenario

Simple Single-Word Project

airbase.json:

{
  "framework": "container",
  "handle": "team/api",
  "port": 3000,
  "instanceType": "nano"
}

URLs:

Production:  https://api.app.tc1.airbase.sg
Staging:     https://staging--api.app.tc1.airbase.sg
Dev:         https://dev--api.app.tc1.airbase.sg


Multi-Word Project Name

airbase.json:

{
  "framework": "container",
  "handle": "analytics/user-dashboard",
  "port": 3000,
  "instanceType": "nano"
}

URLs:

Production:  https://user-dashboard.app.tc1.airbase.sg
Staging:     https://staging--user-dashboard.app.tc1.airbase.sg


Multiple Environments

airbase.json:

{
  "framework": "container",
  "handle": "platform/api-gateway",
  "port": 3000,
  "instanceType": "nano"
}

URLs:

Production:  https://api-gateway.app.tc1.airbase.sg
Staging:     https://staging--api-gateway.app.tc1.airbase.sg
Development: https://dev--api-gateway.app.tc1.airbase.sg
UAT:         https://uat--api-gateway.app.tc1.airbase.sg
Testing:     https://test--api-gateway.app.tc1.airbase.sg


Path Routing

Application Paths

Your application handles all paths:

Base URL:     https://myapp.app.tc1.airbase.sg/
Path routing: https://myapp.app.tc1.airbase.sg/api
              https://myapp.app.tc1.airbase.sg/api/users
              https://myapp.app.tc1.airbase.sg/dashboard
              https://myapp.app.tc1.airbase.sg/static/style.css

All paths are forwarded to your container: - Your application receives the full path - No URL rewriting by Airbase - Configure routing in your application


Example: Express.js Routing

const express = require('express');
const app = express();

// https://myapp.app.tc1.airbase.sg/
app.get('/', (req, res) => {
  res.send('Home');
});

// https://myapp.app.tc1.airbase.sg/api/users
app.get('/api/users', (req, res) => {
  res.json({ users: [] });
});

// https://myapp.app.tc1.airbase.sg/dashboard
app.get('/dashboard', (req, res) => {
  res.send('Dashboard');
});

Example: Flask Routing

from flask import Flask
app = Flask(__name__)

# https://myapp.app.tc1.airbase.sg/
@app.route('/')
def home():
    return 'Home'

# https://myapp.app.tc1.airbase.sg/api/users
@app.route('/api/users')
def users():
    return {'users': []}

# https://myapp.app.tc1.airbase.sg/dashboard
@app.route('/dashboard')
def dashboard():
    return 'Dashboard'

Static Site Routing

Single Page Applications (SPA)

Challenge: Client-side routing vs server-side routing

Solution: Configure fallback to index.html

Example Nginx configuration:

server {
  listen 3000;
  root /usr/share/nginx/html;
  index index.html;

  # Try file, then fallback to index.html
  location / {
    try_files $uri $uri/ /index.html;
  }
}

Enables these URLs to work:

https://myapp.app.tc1.airbase.sg/           → index.html
https://myapp.app.tc1.airbase.sg/dashboard  → index.html (React Router handles /dashboard)
https://myapp.app.tc1.airbase.sg/profile    → index.html (React Router handles /profile)


Static Files

Serve static assets with correct MIME types:

Nginx configuration:

server {
  listen 3000;
  root /usr/share/nginx/html;

  # Static files
  location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
  }

  # SPA fallback for other routes
  location / {
    try_files $uri $uri/ /index.html;
  }
}


HTTPS and TLS

Automatic HTTPS

All Airbase URLs use HTTPS: - TLS certificates are automatically provisioned - Certificate renewal is automatic - HTTP requests are redirected to HTTPS

Example:

http://myapp.app.tc1.airbase.sg
  ↓ (automatic redirect)
https://myapp.app.tc1.airbase.sg


TLS Version

Minimum TLS version: TLS 1.2

Supported versions: - TLS 1.2 ✅ - TLS 1.3 ✅

Cipher suites: Modern secure ciphers only


URL Discovery

Getting Your URL After Deployment

During deployment:

$ airbase container deploy --yes staging

Deployed myapp in staging (team/myapp:staging)
Visit https://staging--myapp.app.tc1.airbase.sg

The URL is displayed in the deployment output.


Listing Deployments

View all environments and their URLs:

$ airbase container list

Environment  URL
-----------  ----------------------------------------
production   https://myapp.app.tc1.airbase.sg
staging      https://staging--myapp.app.tc1.airbase.sg
dev          https://dev--myapp.app.tc1.airbase.sg


Programmatic URL Construction

Building URLs in Code

Node.js:

function getAppUrl(environment = 'production') {
  const projectName = 'myapp';
  const clusterDomain = 'tc1.airbase.sg';

  if (environment === 'production') {
    return `https://${projectName}.app.${clusterDomain}`;
  }

  return `https://${environment}--${projectName}.app.${clusterDomain}`;
}

console.log(getAppUrl('production')); // https://myapp.app.tc1.airbase.sg
console.log(getAppUrl('staging'));    // https://staging--myapp.app.tc1.airbase.sg

Python:

def get_app_url(environment='production'):
    project_name = 'myapp'
    cluster_domain = 'tc1.airbase.sg'

    if environment == 'production':
        return f'https://{project_name}.app.{cluster_domain}'

    return f'https://{environment}--{project_name}.app.{cluster_domain}'

print(get_app_url('production'))  # https://myapp.app.tc1.airbase.sg
print(get_app_url('staging'))     # https://staging--myapp.app.tc1.airbase.sg


URL Best Practices

✅ Do's

  • Use environment variables: Store base URL in configuration
  • Build URLs dynamically: Don't hardcode URLs in multiple places
  • Test in staging first: Verify URLs work before production
  • Use HTTPS in references: Always reference https:// URLs
  • Handle trailing slashes: Be consistent with or without trailing slash

Example configuration:

// config.js
const BASE_URL = process.env.BASE_URL || 'https://myapp.app.tc1.airbase.sg';

module.exports = {
  apiUrl: `${BASE_URL}/api`,
  authUrl: `${BASE_URL}/auth`,
  staticUrl: `${BASE_URL}/static`
};


❌ Don'ts

  • Don't hardcode production URLs: Use environment variables
  • Don't assume URL format: Use provided URLs from deployment
  • Don't use HTTP: Always use HTTPS
  • Don't ignore environment: Different URLs for staging vs production
  • Don't expose internal URLs: Use public URLs in client-side code

Cross-Origin Requests (CORS)

Allowing Requests from Your Frontend

If your API and frontend are on different URLs:

Example: - Frontend: https://app.app.tc1.airbase.sg - API: https://api.app.tc1.airbase.sg

Enable CORS in API (Express.js):

const cors = require('cors');

const corsOptions = {
  origin: 'https://app.app.tc1.airbase.sg',
  credentials: true
};

app.use(cors(corsOptions));

Enable CORS in API (Flask):

from flask_cors import CORS

cors_config = {
    'origins': ['https://app.app.tc1.airbase.sg'],
    'supports_credentials': True
}

CORS(app, **cors_config)


Environment-Specific CORS

Use environment variables:

Node.js:

const allowedOrigins = process.env.CORS_ORIGINS?.split(',') || [
  'https://app.app.tc1.airbase.sg'
];

app.use(cors({
  origin: allowedOrigins,
  credentials: true
}));

.env.staging:

CORS_ORIGINS=https://staging--app.app.tc1.airbase.sg

.env (production):

CORS_ORIGINS=https://app.app.tc1.airbase.sg


URL Limitations

Length Limits

Maximum URL length: 2048 characters (practical limit)

Components: - Domain: Up to 253 characters - Path: Up to 2000 characters

For extremely long URLs: - Use POST requests instead of GET - Store data server-side, pass ID in URL


Reserved Names

Cannot use these as project names: - api (reserved for platform) - auth (reserved for authentication) - admin (reserved for administration) - console (reserved for platform console)

Check availability: Contact platform team if unsure


Troubleshooting

URL Returns 404

Possible causes: 1. Application not deployed to that environment 2. Wrong environment name 3. Application container not responding

Solutions:

# Verify deployment
airbase container list

# Check application logs in Airbase Console
# Navigate to project → Logs → Select staging environment

# Redeploy if needed
airbase container deploy --yes staging


URL Returns 503 (Service Unavailable)

Possible causes: 1. Application crashed 2. Health check failing 3. Container not listening on correct port

Solutions:

# Check logs for errors in Airbase Console
# Navigate to project → Logs → Select staging environment

# Verify PORT binding
# Ensure app binds to process.env.PORT

# Verify health check endpoint works
# Ensure /health endpoint returns 200


CORS Errors

Error: "No 'Access-Control-Allow-Origin' header"

Solution: Enable CORS in your API (see CORS section above)


SSL/TLS Errors

Error: "SSL certificate error"

Possible causes: 1. Using HTTP instead of HTTPS 2. Outdated TLS version on client

Solutions: - Always use https:// URLs - Update client to support TLS 1.2+ - Contact platform team if certificate issues persist


See Also