Skip to content

Getting Started ​

This guide walks you through installing Hedystia and creating your first typed server.

Prerequisites ​

Hedystia requires Bun as its runtime. If you haven't installed it yet:

bash
curl -fsSL https://bun.sh/install | bash

Installation ​

Create a new project and install the required packages:

bash
mkdir my-api && cd my-api
bun init -y
bun add hedystia

To use the typed client in a separate project or package:

bash
bun add @hedystia/client

Your First Server ​

Create an index.ts file:

ts
import 
Hedystia
, {
h
} from 'hedystia'
const
app
= new
Hedystia
()
.
get
('/', () => ({
message
: 'Hello from Hedystia!' }), {
response
:
h
.
object
({
message
:
h
.
string
() }),
}) .
listen
(3000)
console
.
log
('Server running at http://localhost:3000')

Run the server:

bash
bun run index.ts

Visit http://localhost:3000 — you should see:

Response
{
  "message": "Hello from Hedystia!"
}

Adding a Route with Params ​

ts
import 
Hedystia
, {
h
} from 'hedystia'
const
app
= new
Hedystia
()
.
get
(
'/users/:id', ({
params
}) => {
return {
id
:
params
.
id
,
name
: 'Jane Doe' }
}, {
params
:
h
.
object
({
id
:
h
.
number
().
coerce
() }),
response
:
h
.
object
({
id
:
h
.
number
(),
name
:
h
.
string
(),
}), } ) .
listen
(3000)

The h.number().coerce() call tells Hedystia to coerce the URL param (which arrives as a string) into a number before passing it to the handler.

Adding a POST Route ​

ts
import 
Hedystia
, {
h
} from 'hedystia'
const
app
= new
Hedystia
()
.
post
(
'/users', ({
body
}) => {
return {
id
: 1,
name
:
body
.
name
,
email
:
body
.
email
}
}, {
body
:
h
.
object
({
name
:
h
.
string
(),
email
:
h
.
string
().
email
(),
}),
response
:
h
.
object
({
id
:
h
.
number
(),
name
:
h
.
string
(),
email
:
h
.
string
(),
}), } ) .
listen
(3000)

Adding Security ​

Hedystia includes built-in request security. Enable it globally and override per route:

ts
import 
Hedystia
, {
h
} from 'hedystia'
const
app
= new
Hedystia
({
security
: {
bodyLimit
: 1_024 * 1_024,
headers
: {
preset
: 'recommended' },
requestId
: true,
rateLimit
: {
windowMs
: 60_000,
limit
: 100,
key
: 'ip' },
timeout
: 10_000,
}, }) .
get
('/', () => ({
message
: 'Hello from Hedystia!' }))
.
listen
(3000)

See the Framework Overview for full security options.

Using the Client ​

Once your server is running, create a client with full type inference:

ts
import { 
createClient
} from '@hedystia/client'
import type {
app
} from './server' // import just the type
const
client
=
createClient
<typeof
app
>('http://localhost:3000')
// POST /users const {
data
,
error
} = await
client
.
users
.
post
({
body
: {
name
: 'Alice',
email
: 'alice@example.com' },
})
console
.
log
(
data
?.
name
) // 'Alice'

The client proxy mirrors your route structure. Nested paths map to chained properties, dynamic params become function calls.

Next Steps ​

  • Routing — full guide to HTTP routes, params, and groups
  • Context — everything available inside a handler
  • Validation — the h schema reference
  • Error Handling — typed errors and custom responses