Drift is a lightweight, production-ready PowerShell web framework designed for building fast HTTP servers with minimal setup. Drift provides routing, middleware, static file hosting, WebSockets, file-based routing, hot reload for development, and a simple project scaffolding tool.
- HTTP Server using
HttpListener - Router Tree with parameterized routes, e.g.,
/users/[id] - Middleware Pipeline for request processing
- Static File Hosting (
public/folder) - WebSocket Support
- Request Context Helpers:
Html(),Json(),Text(),Body(),Query() - Logging: default and verbose
- Dev Mode: hot reload for
pages/ - File-Based Routing: automatically maps
pages/*.ps1to routes - Project Generator:
drift new <projectName> - Gzip Compression (enabled by default)
- Optional HTTPS with self-signed certificates
Integrated features:
HTTP / HTTPS server
Static server (public/)
Index fallback
Directory index
MIME detection
ETag
Cache-Control
304 responses
Route tree
Parameterized routes [id]
File-based routing (pages/)
Middleware pipeline
Context helpers (Html, Json, Text, Body, Query)
Logging system
Clean cmdlet names + aliases
Cross-platform PowerShell 7 support
WebSocket routes (core support)
Dev mode flag
Safe path resolution
# Import module
Import-Module .\Drift.psm1driftnew mysite
cd mysite
pwsh server.ps1This creates the following structure:
mysite
│
├─ server.ps1
├─ pages/
│ └─ index.ps1
└─ public/
Set-DriftServer -Port 8080 -RootPath "." -LogLevel verbose -Dev-Devenables hot reload for pages-Protocol httpsenables HTTPS (self-signed)
Add-DriftRoute GET "/" {
param($ctx)
$ctx.Html("<h1>Welcome to Drift</h1>")
}
Add-DriftRoute GET "/users/[id]" {
param($ctx)
$ctx.Json(@{ id = $ctx.Params.id })
}Use-DriftMiddleware {
param($ctx, $next)
Write-DriftLog "Incoming request: $($ctx.Request.Url.AbsolutePath)" "Debug"
& $next
}Add-DriftWebSocketRoute "/chat" {
param($socket,$http)
# Handle WebSocket communication
}Any .ps1 file under pages/ automatically becomes a GET route:
pages/index.ps1 -> /
pages/about.ps1 -> /about
pages/users/[id].ps1 -> /users/[id]
Add-DriftRoute POST "/submit" {
param($ctx)
$data = $ctx.Body()
$query = $ctx.Query()
$ctx.Json($data)
}Start-DriftServerServer listens on the configured port and automatically handles routing, static files, and WebSockets.
Write-DriftLog "Server started" "Info"Levels: Info, Warn, Error, Debug
Yes — Drift can absolutely be used as a normal HTTP server. In fact, the framework already contains everything needed to run as a general-purpose web server, not just an API framework.
Because it is built on .NET's HttpListener, it behaves like a lightweight application server similar to:
- Node.js Express
- Go net/http
- Python Flask
But written entirely in PowerShell.
Below are the three main ways Drift can act as a normal HTTP server.
Drift already serves files from the public/ directory.
Example project:
site
│
├─ public
│ ├─ index.html
│ ├─ css
│ │ └─ style.css
│ └─ js
│ └─ app.js
│
└─ server.ps1
Server script:
Import-Module Drift
Set-DriftServer -Port 8080
Start-DriftServerNow open:
http://localhost:8080
Drift will automatically serve:
/public/index.html
/public/css/style.css
/public/js/app.js
So it works like a basic web server (similar to nginx or Apache static hosting).
You can render HTML pages dynamically.
Example:
Add-DriftRoute GET "/" {
param($ctx)
$ctx.Html(@"
<html>
<head>
<title>Drift</title>
</head>
<body>
<h1>Drift Web Server</h1>
<p>Time: $(Get-Date)</p>
</body>
</html>
"@)
}This makes Drift a traditional dynamic web server.
Using the pages/ feature we added.
Structure:
mysite
│
├─ pages
│ ├─ index.ps1
│ └─ about.ps1
│
└─ public
Example pages/about.ps1
param($ctx)
$ctx.Html("<h1>About page</h1>")Now:
http://localhost:8080/about
Works automatically.
This feels similar to:
- Next.js
- Nuxt
- SvelteKit
- Astro
but in PowerShell.
Drift is not meant to replace nginx or Apache for huge production traffic, but it works very well for:
Good Uses:
- internal tools
- dashboards
- admin portals
- API services
- developer utilities
- documentation sites
- microservices
- LAN applications
The router tree we built keeps request handling very fast.
The smallest working Drift server is only 3 lines:
Import-Module Drift
Set-DriftServer -Port 8080
Start-DriftServerNow it acts as a static HTTP server if a public/ folder exists.
Because it is PowerShell, you can do things traditional web servers cannot easily do.
Example:
Add-DriftRoute GET "/disk" {
param($ctx)
$ctx.Json(
Get-PSDrive | Select Name,Free,Used
)
}Instant system API endpoint.
Drift is already capable of being:
| Use Case | Supported |
|---|---|
| Static website hosting | Yes |
| API server | Yes |
| Dynamic web pages | Yes |
| WebSockets | Yes |
| Dev server with hot reload | Yes |
| Microservices | Yes |
MIT License
=== Docs v2
Drift is a lightweight web framework and HTTP server written entirely in PowerShell. It provides a simple and efficient way to build web applications, APIs, and static sites using PowerShell as the runtime.
The framework is designed around a minimal core while still offering modern web features such as routing, middleware, static file serving, caching, compression, and WebSocket support.
Drift can be used as a static web server, a dynamic application framework, or a lightweight API platform.
Drift follows a small set of guiding principles.
Simplicity
The core runtime is intentionally small and readable. A developer should be able to understand the entire framework without navigating thousands of files.
PowerShell Native
Drift does not require a secondary runtime. The framework is implemented completely in PowerShell using .NET networking primitives.
Practical Performance
While Drift is not designed to replace high-performance edge servers like nginx, it performs well for most practical uses such as APIs, dashboards, developer tools, and internal services.
Minimal Dependencies
Drift depends only on PowerShell 7 and the .NET runtime.
Drift requires the following environment.
PowerShell version:
PowerShell 7+
Operating systems supported:
Windows
Linux
macOS
Underlying runtime:
.NET 6+
Drift uses the .NET HttpListener class for HTTP serving.
Drift can be used directly as a module.
Import-Module ./Drift.psm1
In the future Drift may also be published to the PowerShell Gallery.
The smallest possible Drift server requires only three lines.
Import-Module Drift
Set-DriftServer -Port 8080
Start-DriftServer
Once running, Drift listens for requests on the configured port.
http://localhost:8080
If a public directory exists, Drift will automatically serve static files.
A typical Drift project looks like the following.
project
│
├── server.ps1
├── pages
│ └── index.ps1
│
├── public
│ ├── index.html
│ ├── css
│ └── js
│
└── components
Directory descriptions:
server.ps1
Application entry point.
pages/
File-based route handlers.
public/
Static assets served directly by the server.
components/
Reusable script components used by page handlers.
The server is configured using Set-DriftServer.
Example:
Set-DriftServer `
-Port 8080 `
-RootPath "." `
-Protocol http `
-LogLevel verbose
Available parameters:
| Parameter | Description |
|---|---|
| Port | Port the server listens on |
| RootPath | Project root directory |
| Protocol | http or https |
| LogLevel | default or verbose |
| Dev | Enables development mode |
Example enabling development mode:
Set-DriftServer -Port 8080 -Dev
Once configured, start the server.
Start-DriftServer
The console will show the listening address.
Example:
[12:45:10][Info] Drift listening on http://*:8080/
Drift automatically serves files from the public directory.
Example structure:
public
│
├── index.html
├── css
│ └── style.css
└── js
└── app.js
Example URLs:
/ → public/index.html
/css/style.css → public/css/style.css
/js/app.js → public/js/app.js
If a request targets a directory, Drift automatically attempts to serve index.html.
Example:
/docs
will resolve to
public/docs/index.html
Drift automatically determines the correct content type based on file extension.
Examples:
| Extension | MIME |
|---|---|
| html | text/html |
| css | text/css |
| js | application/javascript |
| json | application/json |
| png | image/png |
| svg | image/svg+xml |
Drift implements HTTP caching using two mechanisms.
Each static file generates an ETag hash.
Example response header:
ETag: "A7F19C2A4B"
When a browser requests the same file again it sends:
If-None-Match: "A7F19C2A4B"
If unchanged, Drift returns:
304 Not Modified
This avoids sending the file again.
Static responses include a cache policy.
Example:
Cache-Control: public, max-age=3600
This allows browsers to cache resources locally.
Drift supports gzip compression for compatible clients.
Browsers advertise support using the request header:
Accept-Encoding: gzip
When enabled, Drift compresses responses such as:
html
css
javascript
json
This significantly reduces response size.
Drift supports HTTP range requests.
This allows partial content delivery for large files.
Example header:
Range: bytes=0-1024
Range requests enable:
- video streaming
- large file downloads
- media scrubbing
Drift responds with:
206 Partial Content
Routes allow dynamic request handling.
Routes are registered using Add-DriftRoute.
Example:
Add-DriftRoute GET "/" {
param($ctx)
$ctx.Html("<h1>Hello from Drift</h1>")
}
Drift uses bracket syntax for route parameters.
Example route:
/users/[id]
Example handler:
Add-DriftRoute GET "/users/[id]" {
param($ctx)
$id = $ctx.Params.id
$ctx.Json(@{
user = $id
})
}
Request example:
/users/42
Result:
{
"user": "42"
}
Every handler receives a context object.
param($ctx)
The context exposes helpers for building responses.
$ctx.Html("<h1>Hello</h1>")
$ctx.Json(@{
name = "Drift"
})
$ctx.Text("Hello world")
Example request:
/search?q=test
Access:
$ctx.Query()
Example:
POST /api
Access body:
$data = $ctx.Body()
Middleware runs before route handlers.
Example:
Use-DriftMiddleware {
param($ctx,$next)
Write-DriftLog "Request $($ctx.Request.Url)" "Debug"
& $next
}
Middleware can be used for:
- authentication
- logging
- request validation
- CORS headers
Drift supports file-based routing through the pages directory.
Example directory:
pages
│
├── index.ps1
├── about.ps1
└── users
└── [id].ps1
Routes created automatically:
/ → pages/index.ps1
/about → pages/about.ps1
/users/5 → pages/users/[id].ps1
Example page script:
param($ctx)
$ctx.Html("<h1>About page</h1>")
Drift supports WebSocket routes.
Example:
Add-DriftWebSocketRoute "/chat"
WebSockets allow persistent connections for:
- live updates
- chat applications
- development hot reload
Drift provides a simple logging system.
Write-DriftLog "Server started"
Verbose logging can be enabled.
Set-DriftServer -LogLevel verbose
Log levels:
Info
Warn
Error
Debug
Development mode enables additional runtime features.
Set-DriftServer -Dev
Features include:
- page reload support
- development logging
- simplified debugging
When running Drift in production environments:
- Run behind a reverse proxy such as nginx or Caddy
- Use HTTPS
- Restrict public filesystem access
- Validate request input
Drift works well for several application types.
Examples include:
- internal dashboards
- developer tooling
- microservices
- documentation servers
- REST APIs
- administrative panels
- automation interfaces
Add-DriftRoute GET "/api/time" {
param($ctx)
$ctx.Json(@{
time = Get-Date
})
}
Example request:
GET /api/time
Response:
{
"time": "2026-03-11T12:45:00"
}
Drift is optimized for simplicity rather than extreme throughput.
However the framework includes several performance optimizations:
- route tree matching
- static file caching
- gzip compression
- ETag caching
- directory caching
For very large deployments, Drift can be placed behind a reverse proxy.
Planned areas of expansion include:
- plugin system
- advanced middleware packages
- template rendering
- deployment tooling
- improved WebSocket utilities
Drift is released under the MIT License.