DEV Community

Cover image for GHosttp

Posted on


GHosttp is a tiny development server for developing GCP functions.
With GHosttp, you can choose the folder where your GCP functions reside, allowing you to start developing from there.
Your functions can be developed in Typescript and use the latest ESM features.


The functions framework by Google does not offer a great developer experience when developing an entire backend using GCP.
Whenever you develop or test a new function, you must run the npx @google-cloud/functions-framework --target=myFunction command. Not only is that super long, but it also does not offer hot module reloading.
What if the name changes?
You need to rerun the command. Do you really want to create a bash alias for this library?
Furthermore, their repository shows CommonJS syntax. What if you want to use ESM or Typescript? Since Gen2 is running on Node v20, you could and should leverage ESM. GHosttp is familiar with both ESM and Typescript.

Cloud Run

The Gen2 GCP cloud functions use ExpressJS on top of Cloud Run. ExpressJS comes with a development server. So, why not directly develop it locally in Express and then put it in a Dockerfile? Well, that's a lot of work, and you must be familiar with Docker and Cloud Run. GCP Cloud Functions gen2 abstracts many things for you.


This package is a bit opinionated about developing your GCP function, but I made it as close to the ExpressJS function as possible.
You must name your function handler, and it shall be exported. Below you find a Typescript version.

import type { Request, Response } from '@google-cloud/functions-framework';

export const handler = async (req: Request, res: Response) => {
  res.set('Access-Control-Allow-Origin', '*');
  res.set('Access-Control-Allow-Methods', 'POST');

  // Because of CORS
  if (req.method === 'OPTIONS') {
    res.set('Access-Control-Allow-Methods', 'GET');
    res.set('Access-Control-Allow-Headers', 'Content-Type');
    res.set('Access-Control-Max-Age', '3600');

  // Destructering your request body
  const { message } = req.body;
  res.set('Content-Type', 'application/json');
  return new Response(JSON.stringify(message));
Enter fullscreen mode Exit fullscreen mode


  • GCP account
  • GCP functions gen2
  • Node >= 20 (I haven't tried with 18, but it's a good point to upgrade)

Getting Started

In your repository, just run npx ghosttp --dir path/to/my/functions. That's all. Per default, your backend will run on http://localhost:3000

  ➜ Local:    http://localhost:3000/
  ➜ Network:  use --host to expose

🚀 Loading server entry ./src/run-dev-server.ts GHosttp 12:21:58 AM
✅ Server initialized in 90ms                   GHosttp 12:21:58 AM
👀 Watching ./path/to/functions for changes     GHosttp 12:21:58 AM
ℹ Following endpoints are available             GHosttp 12:21:58 AM
ℹ /logger                                       GHosttp 12:21:58 AM
ℹ /run-dev-server                               GHosttp 12:21:58 AM
Enter fullscreen mode Exit fullscreen mode

It watches whenever you make changes to your function or add a new function. This is great if you want to do Test-Driven-Development and get instant feedback.

Watch the video above to see it in action.


  • --dir - Path to your functions (default ".")
  • --port - Port where your localhost will run (default 3000)

PR and contributions are welcome

Find the repository here:

What's next?

I will add a development server for Flask and Go.
Furthermore, I want to add a new command, npx ghost add-handler my-new-handler --typescript, which scaffolds a new file.
I will also make a blog/video about deploying your ESM/Typescript GCP function ;)

Let me know what you think, and I will be happy to make any contribution 🤩

Top comments (0)