Open demo

Build internal apps using only backend code

Turn your script or CLI into a tool everyone on your team can securely use.
Install
pnpm add @internalstack/server
Declare inputs in backend code
server.ts
import { 
internalStack
} from '@internalstack/server'
import {
addCustomerToDatabase
,
sendWelcomeEmail
} from './utils'
const
server
= await
internalStack
('live_psk_5b2d902f24a057349d9f2d1c385fef7c59')
server
.
statefulSession
(async(
io
, {
user
:
onboardedBy
}) => {
const
customerName
= await
io
.
input
.
text
('Customer name')
// ^ This won't resolve until validated input is received! const
customerEmail
= await
io
.
input
.
email
('Customer email')
await
addCustomerToDatabase
({
customerName
,
customerEmail
,
onboardedBy
,
onboardedAt
: new
Date
().
toISOString
(),
}) await
sendWelcomeEmail
(
customerEmail
)
})
That's all folks!
Your team can now visit https://internalstack.dev/my-startup/onboard-customer, sign in and use the app.
Input validation and authentication built in!
Features

Why build on InternalStack?

Focus on business logic

No more CORS errors, session expired errors, or missing authentication header messages.

Secure

The server runs entirely on-premises. No code or secrets are transmitted.

SSO built in

Users are authenticated and authorized before they hit your server.

Fits right into your workflow

Your code gets committed to your own existing repositories.
Stop wrestling with your tools.
InternalStack saves time and pain on every tool you build.
Move fast and break nothing with full type safety.
server.ts
import { 
internalStack
} from '@internalstack/server'
import {
addCustomerToDatabase
,
sendWelcomeEmail
} from './utils'
const
server
= await
internalStack
('live_psk_5b2d902f24a057349d9f2d1c385fef7c59')
server
.
statefulSession
(async(
io
, {
user
:
onboardedBy
}) => {
const
subscriptionTier
= await
io
.
input
.
radio
<
SubscriptionTiers
>('Subscription tier', [
{
value
: {
name
: 'gold',
price
: 24.99 },
label
: 'Gold' },
{
value
: {
name
: 'diamond',
price
: 34.99 },
label
: 'Diamond' },
{
value
: {
name
: 'netherite',
price
: 49.99 },
label
: 'Netherite' },
])
console
.
log
(
subscriptionTier
.
name
)
const
newSeatCount
= await
io
.
input
.
number
('New seat count')
const
newMonthlyPriceEstimate
= subscriptionTier.name * newSeatCount
The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
const
startDate
= await
io
.
input
.d
})
Pricing

A plan for every team

Hobby

A basic plan for individuals, small teams, and indies.

Free Forever

  • Full component library
  • Up to 10 apps
  • Includes 10 user seats
  • Email support

Pro

Most Popular
A plan for growing businesses that have multiple teams.

$5

/mo

Includes 30 user seats
+$5/mo/additional seat
  • Everything in Hobby
  • Unlimited user seats
  • Unlimited apps
  • Team-level permissions
  • Public apps
  • Priority email support

Enterprise

A comprehensive solution for large organizations with many internal teams.
  • Everything in Pro
  • Request custom components
  • SAML/OIDC SSO
  • SCIM & Directory Sync
  • Dedicated account manager

$250

/mo

Get Started
Includes 30 user seats
+$5/mo/additional seat

Get started today

Build an internal app with authentication in 5 minutes