/ Fly Edge Apps

Getting started with Edge Apps

Thinking about taking Fly for a spin but not quite sure how to navigate? Let me take the wheel and steer you through some of the winding roads and scenic highways that make up the Fly universe. By the end of this article you'll be sitting in the driver's seat and taking your apps from 0 to 100.

In this guide, you'll learn how to get up and running with Fly Edge Apps in just a few simple steps. You'll learn how to build and deploy an application in a full development environment using modern JavaScript and our lightning fast Edge libraries where your content gets optimized as its delivered to your users.

Sound like a good idea? Let's get started!

Step 1: Installation

Install Fly globally: npm install -g @fly/fly
Or inside your project as a devDependency: npm install --save-dev @fly/fly

Note: Make sure you have node.js and npm installed on your computer.

Step 2: Create an index.js file

Write some code to your index.js file: fly.http.respondWith(()=> new Response("My First Fly Edge App"))

Note: Your app must contain an index.js file.

Step 3: Start the fly server

Start up the fly server using the command: fly server
See your app by visiting http://localhost:3000 in your browser.

Hooray! You should see "My First Fly Edge App" when you visit your browser. So, what's even happening here you might ask?

  • Your JavaScript files are being bundled with webpack, a technique used to trim down your application’s load time. With webpack, it’s possible to bundle multiple assets, files, libraries and even images into a single file so your user can load your entire app in a single 'get' request, as opposed to multiple ‘get’ round trips to the server.
  • You have the ability to customize your configuration (e.g. context, entry, output, etc), loaders, and other specific information relating to your build by creating a webpack.fly.config.js file (which will be loaded for you).
  • Fly uses npm packages compatible with the v8 JavaScript engine, so you don't have access to node.js-specific concepts or packages.

At this point you're seeing, "My First Fly Edge App", when you visit your browser. But that’s not all that fun, right? Let's dive a little deeper, unlock the magic of Fly, and learn how we can optimize our app's content for speed and efficiency. Below you will find a few techniques you can use to get the most out of your shiny, new Edge app...

First, it's important to note that Fly specific APIs and functionality Modules are available via the fly Global variable.

Fetch content from anywhere and display it how you want

Create a .fly.yml file to specify properties such as your application's name, configuration settings, and files. By default, fly will read your .fly.yml file in your current working directory.

By specifying a files property in your .fly.yml file, it's possible to use fetch to load files without having to bundle them directly in your JavaScript. The files property here will be an array of files, relative to your .fly.yml to include in deployment. These files can be accessed via fetch("file://path/to/file").

Let's say you're creating an online store and you'd like to pull in a file containing a list of inventory.

# .fly.yml
app: my-online-store
    foo: bar
    - inventory.txt 

Include your inventory.txt file within your files property in .fly.yml to access later.

// index.js
fly.http.respondWith(async function(req){
    if(req.method != "GET") return new Response("not found", { status: 404 });
    const response = await fetch("file://inventory.txt")
    response.headers.set("content-type", "text/html")
    return response

Define an async function. If the request method is not get, return a 404 status and end function. If it is a get request, that’s good! We'll keep going and get that inventory file. Access our inventory.txt file via await fetch. When our response is done loading, set the file's headers to text/html and return. Your inventory list is now available to manipulate any way you'd like.

Now when you navigate to http://localhost:3000/, you should see a list of every product you have available in your online store. This can be particularly useful for pulling in an excel spreadsheet containing products, descriptions, prices, sizes, etc...

Resize and Optimize Images

Now you realize you need some images to represent all that inventory. Use Fly's Image API to enable responsive images and deliver the exact images you need for each user without compromising load time. Here's what it might look like:

require { Image } from '@fly/image'
const resp = await fetch("http://example.com/images/graphic-tee.jpg")
const original = new Image(await resp.arrayBuffer())
let image = original.resize(500).withoutEnlargement()
const accept = req.headers.get("accept") || ""
if (accept.includes("webp")) {
   image = image.webp()
   resp.headers.set("content-type", "image/webp")
image = await image.toImage()
return new Response(image.data, resp)

Fetch the appropriate image from your /images directory and create a new fly image instance. Store the images binary data for speedy inputs and outputs. Resize the output image to 500px (so long as the input image is larger). Convert the image to the webp format for image compression and faster load time. Apply all of our changes and create a new image instance. Finally, create an HTTP Response object and return the image to our loyal customer.

For a fully functional image API example, see the bundled example app.

Prerender React apps for speedy delivery

Undoubtedly, the fastest way to serve a React app to a new visitor is to pre-render it to HTML and load the JavaScript later. Fly gives you the ability to load a React app and send it to your users.

Pre-rendering your React application is also useful if you want to make your app visible to search engines and increase SEO performance. Search engine robots do not typically execute client-side JavaScript code, which makes React apps non-existent on search engine results. Rendering your pages on the server-side and returning html files to the user/search engine robots is a Rockstar solution to this problem.

Our online store needs a contact form incase our customers need to reach us, don’t you think?

import React from 'react' 
import ReactDOMServer from 'react-dom/server'  

fly.http.respondWith(function preRender(response) { 
    const contactForm = React.createElement('form', {className: 'ContactForm'},
        React.createElement('input', { 
          type: 'text', 
          placeholder: 'Name (required)', 
        React.createElement('input', { 
          type: 'email', 
          placeholder: 'Email', 
        React.createElement('textarea', { 
          placeholder: 'Message', 
        React.createElement('button', {type: 'submit'}, "Send") 

   const html = ReactDOMServer.renderToString(contactForm) 
   return new Response(html) 

Create a React form element with whichever input elements you please. In this case, we're asking the user for their name, email and a message. The ReactDOMServer object combined with the renderToString() method enables you to render components to static markup without unsightly, incomprehensible manual markup generation. It works by receiving the React component tree and returning clean and escaped html... basically rendering a React element to its initial HTML. All in all, this method allows us to generate HTML on the server and send the markup down on the initial request, providing faster page loads and search engine crawling for SEO purposes.

Deployment time!

When you feel your app is spick-and-span, deploy to fly.io!

1. Login

If you don't yet have a fly.io account, what are you waiting for? Make one! - https://fly.io/app/sign-up. From the command line, enter fly login. You will be prompted to enter your email address and password (whatever you used to sign up with).

2. Create your app

Create your app from the command line - fly apps create [name]. Name is optional here. If you do not specify a name, one will be created for you.

3. Set your app property

After you create your fly app, you will see something like... App blue-flower-1972 created! Add it to your .fly.yml like: app: blue-flower-1972. Navigate to your .fly.yml file and set your app property to your new app name.

4. Deploy!

Enter fly deploy from the command line. If all your ducks are in a row, you should see:

Deploying blue-flower-1972 
Generating Webpack config... 
Compiling app w/ options: { watch: false, uglify: true } 
Compiled app bundle (hash: 86d857757fd0972e217b08a28455f2d160f2bdba) 
Bundle size: 0.008871078491210938MB 
Bundle compressed size: 0.0021800994873046875MB 
Deploying v1 globally, should be updated in a few seconds. 

Check out your app by visiting app-name.edgeapp.net.

What just happened? Magic, duh.

Ok... if you don’t believe in magic, here's what really happened.

  • Your code was bundled using the module bundler, webpack, which helps you improve performance by giving you control over how assets are built and fetched by the user.

  • Your code was also uglified to save space by automatically removing white spaces, changing big variable names to small ones and compressing files, ultimately reducing the size of the file and helping with performance.

  • Your code, source map and files are added to a simple tarball (a computer file format that combines and compresses multiple files). It's then gzipped to decrease bandwidth and uploaded to the fly.io API using your FLY_TOKEN.

  • We create an immutable "release" to ship your app. Changing anything (by using fly deploy or fly secrets set) will trigger a new release which will be deployed automatically.

  • Your code is distributed across our global fleet of servers faster than you can say abracadabra.

Congrats! You now have a simple Fly app that fetches files, optimizes images and prerenders React elements.

What else can I do with my new Fly app?

The power of Fly also allows you to add unlimited hostnames with a simple POST using our hostname API, test locally using fly test, deliver http requests with unbelievable low latency using fly.cache, connect to any Heroku app, improve your Google Lighthouse Score and more... stay tuned!

Elise Barnes



Elise Barnes

Elise is a former lifestyle blogger, current Full Stack Web Developer/ Technical Content Creator. She loves JavaScript, learning new skills, and explaining challenging concepts to other developers.

New Jersey