> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/stormkit-io/stormkit-io/llms.txt
> Use this file to discover all available pages before exploring further.

# Application Runtime

> Run long-running server processes including Go, Python, and Node.js applications on self-hosted Stormkit instances.

## Overview

Stormkit can run long-running server processes using the **Start command** setting. This is different from serverless functions and is ideal for:

* Go HTTP servers
* Python web applications
* Node.js Express/Fastify apps
* Ruby on Rails applications
* Any application that runs a persistent process

<Warning>
  The Start command option is only available on **self-hosted** Stormkit instances. It is not available on Stormkit Cloud.
</Warning>

## How It Works

When you configure a start command:

1. Build command runs during deployment
2. Build artifacts are packaged
3. Start command launches your server process
4. Server listens on the `PORT` environment variable
5. Traffic is routed to your running server

Unlike serverless functions that spin up on-demand, start command applications run continuously.

## Configuration

### Basic Setup

<Steps>
  <Step title="Navigate to Config">
    Go to **Your App** > **Environments** > **Config**
  </Step>

  <Step title="Set Build Command">
    Configure how to build your application
  </Step>

  <Step title="Set Output Folder">
    Specify where build artifacts are located
  </Step>

  <Step title="Set Start Command">
    Enter the command to start your server
  </Step>
</Steps>

### Required Settings

* **Build command**: Command to compile/build your application
* **Output folder**: Directory containing server executable and files
* **Start command**: Command to start the server process

## Go Applications

Run Go HTTP servers by compiling a binary and starting it with the start command.

### Requirements

* `go.mod` file in your build root
* Go runtime version specified via `.go-version` or `mise.toml`
* Server must listen on `PORT` environment variable

### Runtime Version

<CodeGroup>
  ```bash .go-version theme={null}
  1.22.5
  ```

  ```toml mise.toml theme={null}
  [tools]
  go = "1.22.5"
  ```
</CodeGroup>

### Configuration Example

In **Your App** > **Environments** > **Config**:

| Setting       | Value                                           |
| ------------- | ----------------------------------------------- |
| Build command | `go build -o .stormkit/server/app ./cmd/server` |
| Output folder | `.stormkit`                                     |
| Start command | `./app`                                         |

### Server Code Example

```go cmd/server/main.go theme={null}
package main

import (
    "fmt"
    "log"
    "net/http"
    "os"
)

func main() {
    port := os.Getenv("PORT")
    if port == "" {
        port = "3000"
    }

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello from Go server!")
    })

    http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusOK)
        fmt.Fprintf(w, "OK")
    })

    log.Printf("Server starting on port %s", port)
    log.Fatal(http.ListenAndServe(":"+port, nil))
}
```

### With Gin Framework

```go cmd/server/main.go theme={null}
package main

import (
    "os"
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    
    r.GET("/", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "Hello from Gin!",
        })
    })
    
    port := os.Getenv("PORT")
    if port == "" {
        port = "3000"
    }
    
    r.Run(":" + port)
}
```

### Deployment Flow

<Steps>
  <Step title="Build Phase">
    `go build -o .stormkit/server/app ./cmd/server`

    Compiles your Go code into a binary at `.stormkit/server/app`
  </Step>

  <Step title="Upload Phase">
    The `.stormkit/server` folder is packaged and uploaded as the server artifact
  </Step>

  <Step title="Runtime Phase">
    Start command `./app` executes the binary

    Server listens on `PORT` and handles incoming requests
  </Step>
</Steps>

### Including Assets

If your Go app needs templates, migrations, or other files:

```bash theme={null}
# Copy assets during build
go build -o .stormkit/server/app ./cmd/server && \
cp -r templates .stormkit/server/ && \
cp -r migrations .stormkit/server/
```

All files in `.stormkit/server` are deployed with your binary.

## Node.js Applications

Run Express, Fastify, or any Node.js HTTP server.

### Configuration Example

| Setting       | Value                  |
| ------------- | ---------------------- |
| Build command | `npm run build`        |
| Output folder | `.stormkit`            |
| Start command | `node server/index.js` |

### Server Code Example

```javascript server/index.js theme={null}
const express = require('express')
const app = express()
const port = process.env.PORT || 3000

app.get('/', (req, res) => {
  res.send('Hello from Express!')
})

app.get('/api/health', (req, res) => {
  res.json({ status: 'healthy' })
})

app.listen(port, () => {
  console.log(`Server running on port ${port}`)
})
```

### With TypeScript

```typescript server/index.ts theme={null}
import express, { Request, Response } from 'express'

const app = express()
const port = process.env.PORT || 3000

app.get('/', (req: Request, res: Response) => {
  res.send('Hello from TypeScript!')
})

app.listen(port, () => {
  console.log(`Server running on port ${port}`)
})
```

#### Build Configuration

```json tsconfig.json theme={null}
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "outDir": ".stormkit/server",
    "rootDir": "./server",
    "strict": true
  }
}
```

| Setting       | Value                                                                                         |
| ------------- | --------------------------------------------------------------------------------------------- |
| Build command | `tsc && cp package.json .stormkit/server/ && cd .stormkit/server && npm install --production` |
| Output folder | `.stormkit`                                                                                   |
| Start command | `node server/index.js`                                                                        |

## Python Applications

Run Flask, Django, or FastAPI applications.

### Requirements

* `requirements.txt` or `Pipfile`
* Python version specified via `.python-version` or `mise.toml`
* Server must listen on `PORT` environment variable

### Runtime Version

<CodeGroup>
  ```bash .python-version theme={null}
  3.11.0
  ```

  ```toml mise.toml theme={null}
  [tools]
  python = "3.11.0"
  ```
</CodeGroup>

### Flask Example

```python app.py theme={null}
import os
from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello from Flask!'

@app.route('/health')
def health():
    return {'status': 'healthy'}

if __name__ == '__main__':
    port = int(os.getenv('PORT', 3000))
    app.run(host='0.0.0.0', port=port)
```

#### Configuration

| Setting       | Value                             |
| ------------- | --------------------------------- |
| Build command | `pip install -r requirements.txt` |
| Output folder | `.`                               |
| Start command | `python app.py`                   |

### FastAPI Example

```python main.py theme={null}
import os
from fastapi import FastAPI
import uvicorn

app = FastAPI()

@app.get("/")
def read_root():
    return {"message": "Hello from FastAPI"}

@app.get("/health")
def health():
    return {"status": "healthy"}

if __name__ == "__main__":
    port = int(os.getenv("PORT", 3000))
    uvicorn.run(app, host="0.0.0.0", port=port)
```

#### Configuration

| Setting       | Value                             |
| ------------- | --------------------------------- |
| Build command | `pip install -r requirements.txt` |
| Output folder | `.`                               |
| Start command | `python main.py`                  |

## Environment Variables

### PORT Variable

Your server **must** listen on the `PORT` environment variable:

```javascript theme={null}
// Node.js
const port = process.env.PORT || 3000
```

```go theme={null}
// Go
port := os.Getenv("PORT")
if port == "" {
    port = "3000"
}
```

```python theme={null}
# Python
port = int(os.getenv('PORT', 3000))
```

Stormkit sets `PORT` at runtime. Using a hardcoded port will cause connection failures.

### Custom Environment Variables

All environment variables configured in **Config** > **Environment Variables** are available to your server:

```javascript theme={null}
const dbUrl = process.env.DATABASE_URL
const apiKey = process.env.API_KEY
```

## Static Assets

Serve static files alongside your server application.

### Go Example with Static Files

```go theme={null}
func main() {
    // Serve static files from public directory
    fs := http.FileServer(http.Dir("./public"))
    http.Handle("/", fs)
    
    // API endpoints
    http.HandleFunc("/api/hello", apiHandler)
    
    port := os.Getenv("PORT")
    log.Fatal(http.ListenAndServe(":"+port, nil))
}
```

### Node.js Example with Static Files

```javascript theme={null}
const express = require('express')
const path = require('path')

const app = express()

// Serve static files
app.use(express.static(path.join(__dirname, 'public')))

// API routes
app.get('/api/users', (req, res) => {
  res.json({ users: [] })
})

// Fallback to index.html for SPA
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'public', 'index.html'))
})
```

## Health Checks

Implement a health check endpoint for monitoring:

```go theme={null}
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    w.Write([]byte("OK"))
})
```

```javascript theme={null}
app.get('/health', (req, res) => {
  res.status(200).send('OK')
})
```

```python theme={null}
@app.route('/health')
def health():
    return 'OK', 200
```

## Graceful Shutdown

Handle shutdown signals properly:

### Go Example

```go theme={null}
package main

import (
    "context"
    "log"
    "net/http"
    "os"
    "os/signal"
    "time"
)

func main() {
    srv := &http.Server{
        Addr: ":" + os.Getenv("PORT"),
    }
    
    go func() {
        if err := srv.ListenAndServe(); err != nil {
            log.Fatal(err)
        }
    }()
    
    // Wait for interrupt signal
    quit := make(chan os.Signal, 1)
    signal.Notify(quit, os.Interrupt)
    <-quit
    
    // Graceful shutdown with timeout
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    
    if err := srv.Shutdown(ctx); err != nil {
        log.Fatal("Server forced to shutdown:", err)
    }
    
    log.Println("Server exited gracefully")
}
```

### Node.js Example

```javascript theme={null}
const server = app.listen(port, () => {
  console.log(`Server running on port ${port}`)
})

process.on('SIGTERM', () => {
  console.log('SIGTERM signal received: closing HTTP server')
  server.close(() => {
    console.log('HTTP server closed')
  })
})
```

## Best Practices

### Use Compiled Binaries (Go)

```bash theme={null}
# Faster and more reliable
go build -o .stormkit/server/app
```

```bash theme={null}
# Slower alternative
go run ./cmd/server
```

Compiled binaries start faster and have fewer dependencies.

### Include Dependencies

For Node.js, install production dependencies:

```bash theme={null}
Build command: npm run build && \
  cp package.json .stormkit/server/ && \
  cd .stormkit/server && \
  npm install --production
```

For Python:

```bash theme={null}
Build command: pip install -r requirements.txt -t .stormkit/server/
```

### Log to stdout/stderr

Use standard output for logs:

```go theme={null}
log.Printf("Server started on port %s", port)
```

```javascript theme={null}
console.log(`Server started on port ${port}`)
```

Logs are captured by Stormkit and viewable in deployment logs.

### Set Timeouts

Configure appropriate timeouts:

```go theme={null}
srv := &http.Server{
    Addr:         ":" + port,
    ReadTimeout:  15 * time.Second,
    WriteTimeout: 15 * time.Second,
    IdleTimeout:  60 * time.Second,
}
```

## Troubleshooting

### Server Not Starting

If your server doesn't start:

* Check logs in deployment details
* Verify start command path is correct
* Ensure executable permissions (Go binaries)
* Check for missing dependencies

### Connection Refused

If you can't connect to your server:

* Verify server listens on `PORT` environment variable
* Ensure server binds to `0.0.0.0`, not `localhost`
* Check firewall settings (self-hosted)

### Build Failures

If build command fails:

* Check build command syntax
* Verify runtime version is installed
* Ensure all dependencies are listed
* Review build logs for errors

### Missing Files

If assets or dependencies are missing:

* Verify output folder includes all required files
* Copy assets during build command
* Check that build artifacts are in correct location

## Comparison: Start Command vs Serverless

| Feature          | Start Command                    | Serverless Functions      |
| ---------------- | -------------------------------- | ------------------------- |
| **Execution**    | Continuous process               | On-demand invocation      |
| **Cold starts**  | None                             | Possible                  |
| **State**        | Can maintain in-memory state     | Stateless                 |
| **Use cases**    | Traditional web apps, WebSockets | APIs, SSR, edge functions |
| **Availability** | Self-hosted only                 | Cloud and self-hosted     |
| **Scaling**      | Manual                           | Automatic                 |

## Related Documentation

<CardGroup cols={2}>
  <Card title="How We Deploy" icon="diagram-project" href="/deployments/how-we-deploy">
    Understand folder structure and deployment artifacts
  </Card>

  <Card title="Configuration" icon="gear" href="/deployments/configuration">
    Configure build and deployment settings
  </Card>

  <Card title="System Variables" icon="code" href="/deployments/system-variables">
    Available environment variables
  </Card>

  <Card title="Troubleshooting" icon="wrench" href="/deployments/troubleshooting">
    Fix common deployment issues
  </Card>
</CardGroup>
