voxal docs

Introduction

voxal is a platform for interactive terminal apps that anyone can run with a single SSH command, no install required

voxal is a platform for interactive terminal apps that anyone can run over SSH. You write a small JavaScript app, deploy it with one command, and from then on anyone can use it with ssh your-app@voxal.sh. No frontend to host, no binary to ship, nothing for your users to install. If they have an SSH client, and every machine does, they can run your app.

Think of it as Vercel, except the interface is delivered over SSH instead of the browser. You ship the logic; voxal runs it, renders it live to each user's terminal, and keeps your backend code (API calls, secrets, business logic) on the server where users never see it.

app.js
import { createApp } from '@voxalsh/sdk';

createApp()
  .onConnect((conn) => {
    conn.write('hello from voxal\r\n');
    conn.write('press q to quit\r\n');
  })
  .onKey((conn, data) => {
    if (data === 'q') conn.close();
  })
  .listen();
npm create voxal-app my-app
cd my-app && npm run deploy
# then anyone can run:  ssh my-app@voxal.sh

Start here

What you write

Every voxal app imports one package, @voxalsh/sdk, which gives you two ways to build. Use whichever fits the app.

  • Core. createApp plus a connection object. You handle events and write strings (with ANSI escapes) straight to the terminal. Ideal for small tools, streams, and anything you want byte-level control over.
  • UI (React). @voxalsh/sdk/ui is a real terminal UI framework: flexbox layout, <Box> and <Text>, and hooks like useInput. It mirrors Ink one to one, so React knowledge transfers directly.
app.jsx
import { serve, Box, Text, useInput, useApp } from '@voxalsh/sdk/ui';
import { useState } from 'react';

function Counter() {
  const [n, setN] = useState(0);
  const { exit } = useApp();
  useInput((input, key) => {
    if (input === 'q') exit();
    if (key.upArrow) setN((c) => c + 1);
    if (key.downArrow) setN((c) => c - 1);
  });
  return (
    <Box borderStyle="round" padding={1} flexDirection="column">
      <Text>count: <Text bold color="green">{n}</Text></Text>
      <Text dimColor>up and down to change, q to quit</Text>
    </Box>
  );
}

serve(() => <Counter />);

How it runs

When someone connects, voxal hands the SSH session to your app and nothing else. There is no shell, no login prompt, and no filesystem on the other end. The username in ssh your-app@voxal.sh is your app's name.

Your app runs in an isolated sandbox, one per app, that serves every connected user at once. Each user gets their own connection; your shared logic lives in one place. Idle apps scale to zero and boot again in milliseconds on the next connection, so you only run when someone is actually using your app. Read How voxal works for the full picture.

New here?

The fastest path to a running app is npm create voxal-app. The Quickstart walks through it end to end.

On this page