Open-source project
microsoft/uf2 avatar
microsoft/uf2

UF2: a 512 byte block format for flashing microcontrollers over USB

UF2 file format specification

1,040 stars194 forksJavaScriptNOASSERTION

At a glance

What is it?
UF2 is the file format Microsoft developed for PXT and MakeCode so that a microcontroller can be flashed over mass storage, with the file built from independent 512 byte blocks that carry magic numbers, a target address, a family identifier and optional checksum and extension data. It suits anyone with a board that already has a UF2 aware bootloader, and it is a specification rather than a tool.
Who is it for?
Adopt UF2 if your board ships a UF2 aware bootloader, because the format is deliberately simple enough that a bootloader can implement the file handling in about ten lines of C, and the block structure means a partial copy never reaches the flash. Do not adopt it as a general firmware container, since the format assumes a mass storage device and a bootloader that is already resident on the target.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 30 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why 512 bytes, and why blocks are independent

UF2 is a file format developed by Microsoft for PXT, also known as Microsoft MakeCode, that is particularly suitable for flashing microcontrollers over mass storage, the removable flash drive class of USB device.

The design decision that everything else follows from is the block size. A UF2 file consists of 512 byte blocks, each of which is self-contained and independent of the others. Each block carries magic numbers at the beginning and at the end, the address where the data should be flashed, and up to 476 bytes of data.

The reason for 512 is the transport underneath. The data transfers over mass storage always arrive in multiples of 512 bytes, and together with the FAT file system structure that means the blocks of the UF2 file are always aligned with the writes the device receives, so the microcontroller never gets a partial file.

That single property is what makes the format safe to copy with a drag and drop. A file being written to a removable device can be interrupted at any point, and the guarantee you need is not that the file is complete but that no block is ever half applied. The magic numbers let the microcontroller distinguish a UF2 block from other data, such as a FAT table entry or the various book-keeping files some operating systems store, and once a block is recognised it can be flashed immediately. The only exception is when the flash page size is more than 256 bytes, in which case a buffer is needed.

The specification says the actual handling of the file format during writing is very simple, around ten lines of C in the simplest version. A format that a vendor can implement in a bootloader without a vendor SDK is the whole point of it.

The block layout, field by field

A UF2 file consists of 512 byte blocks. Each block starts with a 32 byte header, followed by data, and a final magic number. All fields, except for the data, are 32 bit unsigned little endian integers.

| Offset | Size | Value | |--------|------|---------------------------------------------------| | 0 | 4 | First magic number, `0x0A324655` (`"UF2\n"`) | | 4 | 4 | Second magic number, `0x9E5D5157` | | 8 | 4 | Flags | | 12 | 4 | Address in flash where the data should be written | | 16 | 4 | Number of bytes used in data (often 256) | | 20 | 4 | Sequential block number; starts at 0 | | 24 | 4 | Total number of blocks in file | | 28 | 4 | File size or board family ID or zero | | 32 | 476 | Data, padded with zeros | | 508 | 4 | Final magic number, `0x0AB16F30` |

The equivalent C structure is short enough to be the entire implementation surface, which is exactly why the specification includes it.

C
struct UF2_Block {
    // 32 byte header
    uint32_t magicStart0;
    uint32_t magicStart1;
    uint32_t flags;
    uint32_t targetAddr;
    uint32_t payloadSize;
    uint32_t blockNo;
    uint32_t numBlocks;
    uint32_t fileSize; // or familyID;
    uint8_t data[476];
    uint32_t magicEnd;
} UF2_Block;

The block number and the total number of blocks are what let a bootloader know that the transfer finished. The specification notes that this requires one bit of memory per block, which on one particular part is 128 bytes, and offers an alternative for bootloaders that would rather not keep that state: implement a reset after about a second of no incoming UF2 blocks.

The flags and what each one turns on

Five flags are currently defined, and each one enables a distinct capability, so they are worth reading as a feature list rather than as bit assignments.

The first, not main flash, means the block should be skipped when writing the device flash. It can be used to store comments in the file, typically embedded source code or debug information that does not fit on the device flash. That is a genuinely useful property, because it lets a build carry its own debug information alongside the image without the bootloader having to understand it.

The second, file container, points at a container structure described in the specification, and the third, family ID present, is the one that carries the board identifier. The fourth, MD5 checksum present, indicates that a checksum is included. The fifth, extension tags present, indicates that the file carries extension data.

So a minimal UF2 file is a header, some data and a trailer, and everything else is opt in through a flag. A bootloader that only understands the first three magic-adjacent fields can ignore the rest, which is the property that lets the format evolve without breaking older bootloaders.

The specification is careful about the relationship between the flags and the fields. The family ID field, for example, should be set only when the corresponding flag is set, and the recommendation to new bootloader authors is to require the field to be set appropriately and refuse to flash UF2 files without it.

Family IDs: the guard against flashing the wrong board

The family ID is the field that makes a UF2 file safe to copy to the wrong device, and the specification spends more words on it than on anything else apart from the layout itself.

The field identifies the board family and usually corresponds to a microcontroller. The rule for a mismatched family ID is absolute: the bootloader should disregard the entire block, including the block number and the total block count fields. And in particular, writing a full UF2 file with a non-matching family ID should not reset the board.

That second clause is the one that prevents damage. A bootloader that resets the board on a file it does not recognise turns a wrong drag and drop into a device that appears bricked until it is power cycled.

The format also allows several files with different family IDs to be simply concatenated together, and the whole resulting file to be copied to the device with only one of them actually being written to flash. So several images for different board types can be concatenated into one file, and the bootloader will pick the one that matches.

If you are developing your own bootloader and your board family is not listed, the instruction is to pick a new family ID at random, and it is good to also send a pull request so the family can be listed. And the guidance on picking random numbers is unusually specific, because collisions in the wild would be a real problem: do not pick them by banging on the keyboard, and do not use values like 0xdeadf00d or 0x42424242. The suggested method is a shell command that combines two random values into a 32 bit identifier, and there is a link to a page on the project site with the same method.

The master list of family IDs is maintained in a JSON file in the repository, utils/uf2families.json, so the registry of who owns which identifier is a machine readable file rather than a table in the documentation.

The rationale behind the odd constants

The specification explains its own choices, and that is one of its more useful features, because several of them look arbitrary until the reason is given.

The magic number at the end of the block is meant to mitigate partial block writes. If the trailing magic is absent, the block was cut short and must not be applied. That is the reason for a second magic rather than a length field, and it is the mechanism that makes the drag and drop copy safe.

The second and final magic numbers were randomly selected, except for the last byte of the final magic number, which was forced to be a newline. Together with the first magic number being the text UF2 with a newline, this makes it easy to identify UF2 blocks in a text editor. A file that is mostly binary still shows its structure when you look at it in an editor, which is a debugging aid of some value.

The header is padded to 32 bytes because hex editors commonly use 16 or 32 bytes as the line length, and this way the data payload is aligned to a line start. Again, this is a decision made for the person debugging with a hex editor rather than for the bootloader.

The choice of 32 bit integers for all the fields is for two reasons, large flash sizes being supported in the future, and simplicity. Little endian is used because most microcontrollers are little endian, and the specification notes that 8 bit microcontrollers can choose to just use the first 16 bits of the various header fields.

Payload sizes and the flash page geometry

The number of data bytes in a block is configurable, and the rule depends on the size of the flash page, which is the smallest size that can be erased on the microcontroller.

If the page size is more than 476 bytes, the bootloader should support any payload size, because it has to buffer the entire page in memory anyway. If the page size is less than 476 bytes, the payload should be a multiple of the page size, so that it can be written without buffering, and the target address should also be a multiple of the page size.

In any event, the payload size and the target address should always be 4 byte aligned.

The specification then gives the piece of practical advice that most implementers want: a payload size of 256 is always correct, and it makes it easy to convert between flash addresses and UF2 file offsets.

The examples show why the rule is not one size fits all. On the Atmel SAMD21 chips the page size is 256 bytes, which is also the payload size. If the page size were 128 bytes, one could use a payload of 128 times three. The Nordic nRF51 has a page size of 1024 bytes, and thus any payload size should be allowed.

The consequence for a file builder is that the payload choice is a property of the target chip, and a builder that targets several chip families has to emit more than one file. The family ID field is what tells the bootloader which of them to apply.

What the repository actually contains

The repository is small, and its shape tells you that this is a specification with tooling attached rather than a program.

At the root there is the README, which is the specification itself, plus a C header, uf2.h, which carries the block structure for implementers, and the LICENSE file. There is a SECURITY.md, and a configuration file for a documentation site.

The directories are where the tooling lives. The uf2tool directory is the command line utility, the patcher directory is the web based patcher that turns a binary into a UF2 file, and the utils directory holds the family ID registry in its JSON form. There are also two companion format documents, cf2.md and hf2.md, which are the specifications of the related formats for other boards.

A subdirectory named hidapi is present alongside a.gitmodules file, which indicates it is pulled in as a submodule.

The practical note for an implementer is that the specification is the product. The header gives you the struct, the README gives you the rules, and the family list gives you the identifiers other people have already claimed. What you build on top of that, a bootloader, a builder, or a flasher, is up to you.

Editorial conclusion

Adopt UF2 if your board ships a UF2 aware bootloader, because the format is deliberately simple enough that a bootloader can implement the file handling in about ten lines of C, and the block structure means a partial copy never reaches the flash. Do not adopt it as a general firmware container, since the format assumes a mass storage device and a bootloader that is already resident on the target. Before you write a bootloader, read the family ID rules, because a bootloader that ignores the family ID can flash the wrong image to the wrong board, and the specification is explicit that a mismatched file should be disregarded entirely.

Frequently asked questions

What is UF2 used for?

It is a file format developed by Microsoft for PXT, also known as Microsoft MakeCode, that is particularly suitable for flashing microcontrollers over mass storage, the removable flash drive class of USB device. A UF2 file consists of 512 byte blocks, each self-contained and independent of the others.

Why is the UF2 block size 512 bytes?

Because data transfers over mass storage always arrive in multiples of 512 bytes, and together with the FAT file system structure that means the blocks of the file are always aligned with the writes the device receives, so the microcontroller never gets a partial file and a block is either applied in full or not at all.

What should a bootloader do with a UF2 file whose family ID does not match?

It should disregard the entire block, including the block number and the total block count fields, and writing a full UF2 file with a non-matching family ID should not reset the board. That is why the format allows files with different family IDs to be concatenated and copied to the device together.

How do I pick a new UF2 family ID for my board?

Pick a new family ID at random, and send a pull request so the family can be listed. The specification asks you not to choose by typing on the keyboard or to use values like 0xdeadf00d, and suggests a shell command that combines two random values into the identifier.

Official sources

  1. Issues
  2. microsoft/uf2 on GitHub
  3. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/microsoft-uf2.svg)](https://hysenlabs.com/projects/microsoft-uf2)

Was this useful?