DEV Community

Alex Spinov
Alex Spinov

Posted on

Val Town Has a Free Serverless API for Running JavaScript in the Cloud

Val Town lets you write and deploy JavaScript/TypeScript functions instantly — no server, no deploy step, no config. Each function gets a URL you can call from anywhere.

Create a Val (Function)

// @username/myApi — instantly deployed at val.town
export default async function(req: Request): Promise<Response> {
  const { name } = await req.json();
  return Response.json({ greeting: `Hello, ${name}!` });
}
Enter fullscreen mode Exit fullscreen mode

Your function is now live at https://username-myapi.web.val.run.

HTTP Vals

// A full API endpoint
export default async function(req: Request): Promise<Response> {
  const url = new URL(req.url);

  if (req.method === 'GET' && url.pathname === '/users') {
    const users = await fetch('https://jsonplaceholder.typicode.com/users');
    return Response.json(await users.json());
  }

  if (req.method === 'POST' && url.pathname === '/webhook') {
    const body = await req.json();
    console.log('Webhook received:', body);
    return new Response('OK');
  }

  return new Response('Not found', { status: 404 });
}
Enter fullscreen mode Exit fullscreen mode

Cron Vals

// Runs on schedule
export default async function() {
  const response = await fetch('https://api.github.com/repos/denoland/deno/releases/latest');
  const release = await response.json();

  if (release.tag_name !== await blob.getJSON('lastDenoVersion')) {
    await email({ subject: `Deno ${release.tag_name} released!`, text: release.body });
    await blob.setJSON('lastDenoVersion', release.tag_name);
  }
}
Enter fullscreen mode Exit fullscreen mode

Built-in Storage

import { blob } from 'https://esm.town/v/std/blob';
import { sqlite } from 'https://esm.town/v/std/sqlite';

// Blob storage
await blob.setJSON('myData', { count: 42 });
const data = await blob.getJSON('myData');

// SQLite
await sqlite.execute('CREATE TABLE IF NOT EXISTS visits (id INTEGER PRIMARY KEY, ts TEXT)');
await sqlite.execute('INSERT INTO visits (ts) VALUES (?)', [new Date().toISOString()]);
const rows = await sqlite.execute('SELECT COUNT(*) as count FROM visits');
Enter fullscreen mode Exit fullscreen mode

Why This Matters

  • Zero deploy: Write code, it is live instantly
  • Free tier: 10K requests/day
  • Built-in storage: Blob + SQLite included
  • Import anything: ESM imports from npm or URLs

Need custom serverless tools or API automation? I build developer tools. Check out my web scraping actors on Apify or reach out at spinov001@gmail.com for custom solutions.

Top comments (0)