Your prototype works. Can someone set up the second board?

You have a working demo, and a colleague needs another one for a user test. You send them main.py. Their board stops with a missing-module error, or starts fine but behaves differently. The application file was only part of what made the first prototype work.

For a small team, this is often the first software handover that matters. Someone should be able to recreate the demo without borrowing your laptop or guessing which files you installed last month. That means keeping the board firmware, the supporting libraries and one useful functional check together.

On our bench we walked through MicroPython's library-installation routes on a WIZnet Ethernet board: downloading on the board, installing readable source instead of bytecode, and installing from a computer. Each one turned up a way a second board can end up different from the first.

Start with the board that already works

Firmware is the software under your application. It decides which hardware interfaces and built-in modules exist. Before changing anything, record the working board's exact model, firmware build and library files, and keep a copy of that setup.

This matters even when both environments say "MicroPython." In a MicroPython GitHub discussion from September 2026, a developer could not find mip in a Unix container; the fix was a different build variant. Check what a build includes before treating every missing import as a failed download.

Our own records were a warning here: the board and firmware labels in our code and our version notes did not agree, so they could not identify one exact setup. Use the identity reported by the working device, not labels copied between documents.

Choose how the libraries reach the board

There are two useful routes. A networked board can download a library itself, or a computer can download it and copy it over the local connection. The second is handy when the demo unit has no network yet.

For an on-board download, once networking is up, at the MicroPython prompt:

import mip
mip.install("random")

random is just a test package. mip uses MicroPython's own package index by default, not the desktop Python index, and installs into a directory on the board's import path that varies by board. The MicroPython package management guide covers the details.

Our log reached the install message, but an Ethernet fatal error earlier in the same log was still visible. A success line at the end does not mean the setup was clean; read the whole log.

We then called random.randint(0, 10), which returned 7, and listed the library directory, which held random.mpy. A function that runs and returns a plausible result is better evidence than a download message. There is still a trap: some firmware already includes random, so the call does not prove the downloaded file supplied it. For your own sensor or display driver, choose a check that identifies the expected library and exercises the feature your demo needs.

Keep the file you meant to install

Installing readable Python source instead of compiled bytecode helps when your team needs to inspect or change a driver. We tried a URL-based download and ended up with a file named random.py. A filename does not establish its contents: a GitHub browser-page URL can return an HTML page, not Python. For a package in the official index, the documented source option is mip.install("random", mpy=False). For a third-party driver, follow its documented install location and record the revision you chose.

If you ship compiled .mpy files, record their compatibility with the firmware. The MicroPython .mpy reference explains the version and architecture requirements, and why a same-named .py next to an .mpy can change which one is imported. Experiment on a spare board, never by deleting files from the only working demo.

Make one repeatable installation route

A third-party installer we tried put library files under /lib but left one file at the filesystem root. A colleague following a mix of old commands can build a different environment even though every command reports success. Pick one route and write down the destination, package revision and dependencies.

The last route runs on the computer. With mpremote installed and the board connected:

mpremote mip install abc

This goes in the computer's terminal, not at the board's Python prompt, and abc is another demonstration package; substitute your actual dependency after checking its instructions. In our run, mpremote installed abc.mpy over COM3 (that port is ours, not a universal setting), and listing /lib on the board showed it next to random.py.

Finish with the behavior your colleague needs

For a temperature logger, a good handover check might be: start from power-off, take one sensor reading, save one record. For a display prototype: power up, draw the expected screen, respond to a button. These are suggested checks; what we showed is package installation and a small function call, not either product.

Give the next person three things: the firmware and board identity, the application with its exact library set, and a short test with an expected result. Run the test on the second board after a fresh restart. Keep private network settings out of the shared instructions.

Later you might build the libraries into a custom firmware image, which MicroPython calls frozen modules. That changes how updates are built and delivered, so treat it as a separate engineering decision. You do not need it to make a second demo unit understandable and repeatable.