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
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 PopularA 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