v1.1.0 — 26 built-in middleware

Express API.Bun speed.

Drop-in replacement. One import replaces 15+ npm packages.
Same (req, res, next). Zero rewrites.

0dependencies
23built-in middleware
97%+Express compat
app.ts
bunWay
import { bunway, cors, helmet, json, session } from 'bunway'

const app = bunway()

app.use(cors({ origin: true }))
app.use(helmet())
app.use(json())
app.use(session({ secret: 'keyboard cat' }))

app.get('/users/:id', (req, res) => {
  res.json({ id: req.params.id })
})

app.post('/users', validate({
  body: { email: { required: true, type: 'email' } }
}), createUser)

app.listen(3000)
// That's it. No npm install. No config.

What's inside

Everything included.
Nothing to install.

Every package Express developers reach for — already inside bunWay. No npm install. No version conflicts. No supply chain risk.

replaces helmet · csurf · express-rate-limit · hpp
import { bunway, helmet, cors, csrf, rateLimit, hpp } from 'bunway'

const app = bunway()

app.use(helmet())                           // 14 security headers
app.use(cors({ origin: /\.myapp\.com$/ }))  // CORS + preflight
app.use(rateLimit({ windowMs: 60_000, max: 100 }))
app.use(csrf())                             // double-submit cookie
app.use(hpp({ whitelist: ['tags'] }))      // parameter pollution
15+npm packages replaced·0transitive dependencies·26middleware, all fully typed

Real-world patterns

Built for how you
actually ship.

REST APIs, WebSocket servers, file upload endpoints — bunWay handles them all. One import. No plugins.

REST API

Validation · rate limiting · CORS

import { bunway, json, cors,
         rateLimit, validate } from 'bunway'

const app = bunway()

app.use(cors(), json())
app.use(rateLimit({ max: 100 }))

app.post('/users',
  validate({ body: {
    email: { required: true, type: 'email' }
  }}),
  (req, res) => res.json({ ok: true })
)
app.listen(3000)
cors()json()rateLimit()validate()

Real-time WebSocket

Native Bun WS · no extra packages

import { bunway } from 'bunway'

const app = bunway()

app.ws('/live', {
  open(ws) {
    ws.send('connected')
  },
  message(ws, msg) {
    ws.send(`echo: ${msg}`)
  },
  close(ws) {}
})

app.listen(3000)
// ws://localhost:3000/live
app.ws()openmessageclose

File Upload & Serve

Uploads · static serving · ETag caching

import { bunway, upload,
         serveStatic } from 'bunway'

const app   = bunway()
const store = upload()

app.use('/files', serveStatic('./uploads'))

app.post('/upload',
  store.single('photo'),
  (req, res) => res.json({
    name: req.file?.originalname
  })
)
app.listen(3000)
upload()single()serveStatic()ETag

Express → bunWay

Your existing code.
One import changed.

Everything else stays exactly the same. No rewrites, no new patterns to learn.

BeforeExpress + 14 packages
$ npm install express
$ npm install cors helmet
$ npm install express-session
$ npm install morgan compression
$ npm install express-rate-limit
$ ...9 more packages
+ 26 transitive dependencies
const express = require('express')
const cors    = require('cors')
const helmet  = require('helmet')
const session = require('express-session')
// 10 more require() calls...
AfterbunWay
$ bun add bunway
# that's it.
import { bunway, cors, helmet,
         session } from 'bunway'
// cors, helmet, session already inside
// nothing else to install

Everything below stays identical

app.ts
unchanged
const app = bunway()  // was: express()

app.use(cors())
app.use(helmet())
app.use(session({ secret: 'keyboard cat' }))

app.get('/users/:id', (req, res) => {
  res.json({ id: req.params.id })
})

app.listen(3000)

Start now

Start in 30 seconds.

One command. No config. Your Express app runs on Bun today.