Improve this doc
Getting Started with and

Looking for other boards documentation? Click here.

Getting Started With Jetson TX2 and Node.js


In this guide we will build a simple Node.js web server project on a Jetson TX2. At its most basic, the process for deploying code to a Jetson TX2 consists of two major steps:

  • Setting up your Jetson TX2 with resinOS, the host OS that manages communication with and runs the core device operations.
  • Pushing your Node.js project to the image builder, which pulls in all necessary dependencies and creates the container image for your application.

Once these steps are finished, your Jetson TX2 will download the container image, kick off your application, and begin sending logs to your dashboard!

What you will need

  • An Nvidia Jetson TX2, along with the baseboard that allows flashing from an SD card.
  • A 4GB or larger microSD card. The speed class of the card also matters - class 10 card or above is the way to go.
  • An ethernet cable.
  • Compatible power supply.
  • A account.

Need help?

If you find yourself stuck or confused, help is just a click away:

  • The troubleshooting section of the forums is where our engineers address any issues you may be having with

  • We also have a community chat for more general discussion.

  • You can read about our approach to support at

Account setup

If you don't already have a account, make sure to sign up.

Adding an SSH Key uses git to push code from your computer to a dedicated repository. As part of the account creation process, you will be asked to add a public SSH key. The SSH key secures your connection to our server, letting us know you have the authority to make changes to the repository.

Note: You can click Skip to move past this step for now, but you will not be able to push code to your Jetson TX2 until you have added a public key to your account. This can be done at any time from the Preferences page on the dashboard.

If you have a public SSH key, simply paste it into the box provided and click Save Key:

You can also import your key from GitHub. If you choose this option, you will be asked to enter your GitHub username:

Don't have an SSH key?

If you are unfamiliar with SSH keys, we recommend you take a look at GitHub's excellent documentation. This will walk you through everything you need to create a key pair. Window's user? Be sure to check out these instructions.

Create an application

An application is a group of devices of the same type that all run the same code. When you provision a device, it is added to a specific application, but can be migrated to another application at any time.

To create an application, simply select the Jetson TX2 type from the drop-down list, type in a name, and click Create new application:

This will take you to the dashboard for your newly created application, where you can manage your whole fleet of Jetson TX2s.

Add your first device

To connect with, your Jetson TX2 will need a resinOS image that is configured for your application and your network. Start by clicking Add device in your application dashboard:

A list of available resinOS versions is shown in the dropdown. In general, the most recent version is recommend. You can also select whether you would prefer a Development or Production edition with a toggle:

Note: When you're first getting started, a Development image will be most useful, as it permits a number of testing and troubleshooting features. For production use, be sure to switch to a Production image. More details on the differences between Development and Production images can be found here.

A toggle is also used to select whether your network connection will be through Ethernet Only or with the option for WiFi + Ethernet. Selecting Wifi + Ethernet allows you to enter a WiFi SSID and WiFi Passphrase:

Clicking Advanced presents the option to select the rate at which your device checks for updates and the option to download just a configuration file (config.json) rather than an entire image:

Once you have finished your image configuration, click the Download resinOS button. When the download completes, you should have a zipped image file with a name like, where FirstApp is the name you gave your application on the dashboard.

Create a bootable SD card

The next step is to flash the downloaded image onto your SD card using Etcher, a simple, cross platform SD card writer and validator. Once you have Etcher installed, start it up. To give Etcher access to your SD card, your system may prompt you to grant administrative privileges.

To create a bootable resinOS SD card follow these steps:

  1. Click Select image and find your application's resinOS image file.
  2. If you haven't already done so, insert your SD card into your computer. Etcher will automatically detect it. If you have more than one SD card inserted, you will need to select the appropriate one.
  3. Click the Flash! button.

Etcher will now prepare a bootable SD card and validate that it was flashed correctly. This can take roughly 3 or more minutes depending on the quality of your SD card. You'll get a little ping when it's done, and Etcher will safely eject the SD card for you.

Note: You can burn several SD cards with the same image file and all the devices will boot and provision into your application's fleet. You can also disable the auto-ejecting or validation steps from the Etcher settings panel.

Provision your device

Make sure your Jetson TX2 development board is powered off. Insert the SD card from the previous step and plug in the power cord. Press and hold the power button for one second to turn the device on.

Note: This will also completely erase internal storage media, so please make a backup first.

At this point your device will attempt to connect to the internet. If you selected WiFi as your connectivity type, remember to attach the WiFi antennas before booting the board. If you selected ethernet, make sure your ethernet cable is plugged in. Your device should show up on the dashboard in 10 minutes or less.

After the device has been provisioned, it will shut itself off automatically. You can safely remove the SD card.

Your Jetson TX2 is now ready to run an application. Press the power button once more to turn it on, and get ready to make your first code deploy!

Deploy code

Now that we have a device or two connected to a application, lets deploy some code and actually start building something.

A nice first project to get your feet wet is a simple Express.js web server which will serve a static page on port :80. All the project source code can be found here on github.

To clone the project, run the following command in a terminal or your preferred git client:

$ git clone

Once the repo is cloned, change directory into the newly created simple-server-node directory and add the resin git remote endpoint by running the command git remote add shown in the top-right corner of your application page:

$ cd simple-server-node
$ git remote add resin <USERNAME><USERNAME>/<APPNAME>.git

Note: On other git clients there may be an alternative way to add a remote repository.

So now we have set up a reference in our local git repository (the one on our development computer) to the application remote repository. So when we push new changes to this remote repository it will get compiled and built on our servers and deployed to every device in the application fleet.

Warning: The git repository is not intended as a code hosting solution, and we cannot guarantee the persistence of data in git remotes.

Now to deploy this code to all device(s) in the application just run the command:

$ git push resin master

If you want to completely replace the source code of the application with a new source tree, you may need to force the push by running git push resin master --force, due to how git works.

Note: On your very first push, git may ask you if you would like to add this host to your list of allowed hosts. Don't worry about this, just type 'yes' and carry on your merry way.

You'll know your code has been successfully compiled and built when our friendly unicorn mascot appears in your terminal:

This means your code is safely built and stored on our image registry. It should only take about 2 minutes to build your code and subsequent builds will be quicker because of build caching.

Your application will now be downloaded and executed by all the devices you have connected in your application fleet. You may have to wait about 6 minutes for the first push... So time for more tea, but don't worry, all subsequent pushes are much, much faster due to Docker layer sharing. You can see the progress of the device code updates on the device dashboard:

You should now have a node.js web server running on your device and see some logs on your dashboard. If you go to the Actions page for your device, you can enable a public URL, this URL is accessible from anywhere in the world.

If you follow the URL, you will be served a page saying "Hello, World!". Alternatively you can point your browser to your devices IP address.

You should now have a basic idea of how to deploy a node.js application on If you feel like you have a handle on Docker and Node.js projects, then skip over the next section and go straight to "Using the web terminal".

Let's dive into the code

So in the root directory of our project we see a number of files, the most important ones to focus on are:-

  • Dockerfile.template : This is basically a recipe file on how to build and run our application container.
  • package.json : This is a JSON file that describes how our node.js project is built, what dependencies it has and it's entry point. Read more about it on the npm docs.
  • server.js : This is the entry point to our application code and is where all the fun happens!

The most important part of a project repo is usually the Dockerfile or Dockerfile.template. The .template version allows you to define template variables like %%RESIN_MACHINE_NAME%% which enables you to push the same repository to multiple different architecture fleets.

If we look at our Dockerfile.template, the first thing we see is:

FROM resin/%%RESIN_MACHINE_NAME%%-node:slim

This line has quite a bit packed into it. The first thing that happens is that the %%RESIN_MACHINE_NAME%% place holder gets stripped and replaced with the resin device name. For example if your application type is a Jetson TX2, the line will be replaced with:

FROM resin/jetson-tx2-node:slim

Which tells the resin builder that this is the Docker image we want as our base. Checkout the full list of official resin device names and the matching Docker Hub base images.

We also have a :slim tag associated to the base image which denotes that we want the stripped down version only contains the minimal packages needed to run node, so no node-gyp and other build-essentials. If you need to build some native modules, say node-i2c, you should switch to :latest tag. We also have a number of pinned version tags, which should be used for production devices. Checkout the full list of -node tags, if you want to target a specify node.js version or a fixed date build.

Next up we have 3 line which were commented out:

RUN apt-get update && apt-get install -yq \
   alsa-utils libasound2-dev && \
   apt-get clean && rm -rf /var/lib/apt/lists/*

This is just a demonstration of how you can use apt-get to install dependencies in your container. In this case we would install some useful linux sound utilities.

The next two directives are pretty straight forward and key parts of using Docker.

# Defines our working directory in container
WORKDIR /usr/src/app

# Copies the package.json first for better cache on later pushes
COPY package.json package.json

As the comments say, WORKDIR set our working directory for any RUN, COPY or CMD commands following it. So the next line would effectively COPY our package.json in the root of our directory to usr/src/app/package.json. Check out the Docker reference pages for more info on these commands.

We can now build all our node.js modules and dependencies, this is done using the RUN command. We also build with the --production flag and clear the cache in the same step in order to keep the final image size smaller.

# This install npm dependencies on the build server,
# making sure to clean up the artifacts it creates in order to reduce the image size.
RUN JOBS=MAX npm install --production --unsafe-perm && npm cache clean && rm -rf /tmp/*

# This will copy all files in our root to the working  directory in the container
COPY . ./

# Enable systemd init system in container

# server.js will run when container starts up on the device
CMD ["npm", "start"]

After the npm install we copy the rest of our source code into the working directory, we do this after so that later builds can benefit from build caching. So we will only trigger a full npm install if we change something in package.json.

The last 2 commands are runtime directives. The ENV INITSYSTEM on is used to enable the systemd init within the container. This is useful for a number of reasons, like keeping the container open after application crash and handling /dev updates as new USB devices are plugged in. If you don't want an init system, just set it to off or remove the line for the Dockerfile.

The last command, CMD is perhaps one of the most important. This command defines what will run at container start on your Jetson TX2, in our example we have told npm to start a process. It should be noted that you can only have one CMD per Dockerfile.

In our package.json the parts to focus on are our "scripts" and "dependencies":

  "name": "simple-server-node",
  "version": "1.0.0",
  "description": "A simple Expressjs Web server on",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node server.js"
  "dependencies": {
    "express": "*"

The "dependencies" section allows us to define node modules and their versions we want to use in our application. For a production application we recommend pinning the versions.

The "scripts" allow us to point to the server.js as our starting point for the whole application, so we get our awesome "Hello, World!" server when the container starts up :)

Use the web terminal

Often while developing and deploying code, it helps to run a few test commands or check some log files. For this resin has a handy built in web terminal which you can use from the comfort of your dashboard, or command line (check the later section on CLI and resin sync for this).

To fire up a terminal session on your device you need to two things:

  1. An online device.
  2. A running container.

Number .1 is usually pretty easy, but number .2 catches people pretty often. Since if the main process of the Docker container crashes or ends, the container effectively stops and there is nothing for the web terminal to SSH into :( . For this reason we normally recommend using the systemd init system during development as this will ensure your container is always up and running, even if your application code crashes.

To start a session, just navigate to the >_ Terminal page for the device and hit the "Start the terminal session" button. It will take a few seconds to establish a connection and then you are good to go.

Note: Currently if you navigate away from the >_ Terminal page, you session will be killed. This is a known issue and will be remedied very soon.

Use resin sync to develop quickly

Okay, so now we know how to provision a device and push code. There is just one glaring problem...

Do I really have to go through the whole git add, git commit, git push dance every time I forget a semicolon?

Luckily, our nifty little command line tool resin sync is here to save the day. It allows you to quickly sync source code and file changes across to one of the devices in your fleet, so you can rapidly iterate code on this test device before releasing it to the whole fleet.

Note: Resin sync will only work on ResinOS v1.1.4+ and Agent v1.8.0+.

Setting up resin sync.

Resin sync is bundled in with our handy resin CLI. The CLI allows you to basically do all your management from the comfort of the command line. Read the CLI reference more info on all the cool things it can do.

Warning: Currently resin sync is NOT supported on Windows. Support is currently being worked on, you can check the progress on this on the git repository.

To install resin CLI and sync you need at least node.js 4.0.0 on your development machine, then run:

$ npm install --global --production resin-cli

You may need to run the install with admin privileges depending on how you have installed node.js.

Note: If you already have resin CLI installed, you will need to upgrade to resin-cli v4.0.0+

Once the CLI is installed globally, login with your resin account:

$ resin login

You should then be presented with 3 options to login. The recommended method is Web authorisation which will open a dialog in your web browser and ask you to authorise the use of the CLI.

resin:simple-server-node shaun$ resin login
______          _         _
| ___ \        (_)       (_)
| |_/ /___  ___ _ _ __    _  ___
|    // _ \/ __| | '_ \  | |/ _ \
| |\ \  __/\__ \ | | | |_| | (_) |
\_| \_\___||___/_|_| |_(_)_|\___/

Logging in to
? How would you like to login? (Use arrow keys)
❯ Web authorisation (recommended)
  Authentication token
  I don't have a Resin account!

Setting up Node.js cross-compilation

Cross-compilation is not needed when using resin sync and Node.js as it is an interpreted language. Interpreted languages are programming languages in which programs may be run from source code form, they do not need to be compiled.

Using resin sync

You are now ready to start using resin sync, so open a terminal in the directory which we were using earlier in this guide. Make a trivial change to your source code and then run:

$ resin sync --source . --destination /usr/src/app

It should prompt you to select a device, then it will sync all the files in the root of your directory to /usr/src/app on your selected device and finally it will restart the container. You should see something similar to:

resin:simple-server-node shaun$ resin sync --source . --destination /usr/src/app
Getting information for device: 5dc2c87ea2caf79bc4e25ae638c6d5a35a75cecf22e8f914331dcb2f588f4b
Application container stopped.
Synced /usr/src/app on 5dc2c87.
Application container started.

resin sync completed successfully!

Your new code changes should be up an running in under 30 seconds, Great success!!

Some Notes and Caveats on Resin Sync
  • Resin sync directly syncs all the files in the root of your directory to the selected destination directory on your device. If you are using a compiled language you will need to set up cross-compiling on your local development machine and include a .resin-sync.yml file that tells resin sync how to compile your code and sync the resulting executable.

  • It is not possible(~easy) to install dependencies using resin sync. So if you need to do an apt-get or add something to either your Dockerfile, package.json or requirements.txt, then you will need to go through the standard git push resin master build pipeline.

  • If you know the device UUID you can just run: resin sync <uuid>. This is useful for using resin sync programmatically, in say a gulp workflow, as it does not require interactive action to confirm the destination device.

  • If no --destination / -d option is set, an interactive dialog will ask you to provide a destination directory. You can skip this by hitting 'enter' and resin sync will use the /usr/src/app device directory as the default sync destination.

  • After every resin sync the updated settings are saved in .resin-sync.yml in your projects's local directory and will be used in later invocations. You can also change any option by editing '.resin-sync.yml' directly.

  • A caveat, if you are using a DSA key, some newer openSSH clients do not allow them by default. So you may have to add the following option to ~/.ssh/config : PubkeyAcceptedKeyTypes=+ssh-dss

  • Resin sync is currently permitted to device owners only. The owner of a device is the user who provisioned it, so you will not be able to use resin sync on devices of shared applications that you did not provision.

One last Tip!

One of the many useful features of resin-cli is resin ssh, this command allows you to quickly SSH into a device's running container and run test commands or pull out some logs.

Provided you are already logged in on the CLI and you have a device online, you can use resin ssh <uuid> to access the container. Here is an example:

resin:simple-server-node shaun$ resin ssh 5dc2c87
Connecting with: 5dc2c87
[email protected]:/# uname -a
Linux Jetson TX2-5dc2c8 3.10.93 #1 SMP PREEMPT Wed Apr 20 10:25:12 CEST 2016 aarch64 GNU/Linux

Example projects

There are even more hidden treasures in the platform and tools, but we will get into those a bit later. For now why not fork one or two of our example projects and build something grand.

SORRY! we currently don't have any other Node.js projects for the Jetson TX2. How about submitting one to us at [email protected]?

Enjoy Resinifying All the Things!