Library / SDK
symforce-org/symforce avatar
symforce-org/symforce

SymForce: symbolic code generation and factor-graph optimization for robotics

Fast symbolic computation, code generation, and nonlinear optimization for robotics

1,641 stars178 forksC++Apache-2.0

At a glance

What is it?
SymForce turns symbolic math written with a SymPy-style API into generated C++ or Python, then solves factor-graph problems with tangent-space optimization. It is built for SLAM, calibration and state estimation work where handwritten Jacobians are the main source of bugs.
Who is it for?
Adopt SymForce if you are writing state estimation, bundle adjustment or calibration code and want derivatives generated rather than hand-derived, and if your team can absorb a CMake dependency for the C++ side. Do not adopt it if you need a pure Python runtime with no code generation step, or if your problem has no Lie group structure to exploit.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 22 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

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

DEEP OPEN-SOURCE ANALYSIS

The handwritten-derivative problem SymForce targets

Robotics estimation code has a recurring failure mode. You write a residual, you derive its Jacobian by hand, and the derivation is wrong in a way that still converges, just slower or to a slightly wrong answer. SymForce exists to remove that step. The README describes the library as combining symbolic mathematics with autogenerated, highly optimized code in C++ or any target runtime language, and states that SymForce automatically computes tangent space Jacobians, eliminating the need for bug-prone handwritten derivatives.

The audience is narrow and specific. The topics list names SLAM, structure-from-motion, motion planning, computer vision and autonomous vehicles. The pyproject.toml classifiers include Scientific/Engineering, Code Generators and Embedded Systems. This is not a general-purpose math library for a web backend. It assumes you have poses, rotations and landmarks, and that you want derivatives with respect to a tangent space rather than raw parameter coordinates.

That last assumption is the whole point. A rotation matrix has nine entries and three degrees of freedom. Naive differentiation gives you a 3x9 Jacobian with a null space in it. SymForce parameterizes the update in the tangent space instead, so the Jacobian has the shape the optimizer actually wants. If your variables are plain unconstrained vectors, this machinery buys you nothing.

Three systems in one repository, and how they connect

The README splits the project into three independently useful pieces. The Symbolic Toolkit builds on the SymPy API and adds geometric and camera types, Lie group calculus, singularity handling, and tools for modeling problems. The Code Generator transforms symbolic expressions into branchless code with minimal dependencies, and has a template system to target any language. The Optimization Library is a tangent-space optimizer based on factor graphs, implemented in C++ and Python.

The data flow is one-directional. You write expressions in Python using symforce.symbolic, which is the augmented SymPy API. Those expressions are symbolic objects. You ask for a Jacobian, and SymForce produces another symbolic expression. Then the code generator emits source for that expression. The generated function can then be plugged into the optimizer as a factor. Nothing runs the symbolic layer at deployment time. The symbolic work happens at development time, and what ships is the generated code.

That split is why the README can claim the generated functions are directly usable as factors in the optimizer. There is no adapter layer between the two halves. It is also why the repository contains a gen/ directory and a templates concept: the generated output is a build artifact you are expected to check in or compile, not something produced on the fly. The claim of 10x speedups over standard autodiff appears in the feature list as something the sparsity and flattening strategies can yield; the README does not attach a benchmark or a specific problem to that number.

Installing SymForce and running the 2D localization example

The README gives a single install command. It installs pre-compiled C++ components on Linux and Mac using pip wheels, but the README states plainly that it does not include C++ headers. If you want to compile against C++ SymForce types such as sym::Optimizer, you need to build from source.

bash
pip install symforce

To confirm the install worked, the README suggests this check in Python. It imports the symbolic API and constructs an empty Rot3, which exercises the geometry types.

python
>>> import symforce.symbolic as sf
>>> sf.Rot3()

The tutorial then builds a small 2D problem. A robot moves through a plane, measures distance travelled from odometry, and measures relative bearing angles to known landmarks. The goal is to estimate poses at multiple time steps from noisy measurements. The first step is to declare symbolic variables for a pose and a landmark.

python
import symforce.symbolic as sf

pose = sf.Pose2(
    t=sf.V2.symbolic("t"),
    R=sf.Rot2.symbolic("R")
)
landmark = sf.V2.symbolic("L")

The pose is represented as world_T_body, so transforming a world-frame landmark into the body frame is an inverse multiply. The README shows the resulting expression expanded, and notes that sf.Rot2 is stored internally as a complex number, which is why the output is written in terms of R_re and R_im.

python
landmark_body = pose.inverse() * landmark

The payoff comes next. Asking for the Jacobian of the body-frame landmark with respect to the tangent space of the pose, parameterized as (theta, x, y), returns a symbolic matrix. This is the derivative you would otherwise derive by hand. From here the README's path continues into generating code from the expression and using it as a factor, which is where the optimizer takes over.

Where SymForce is the wrong tool

The dependency on a code generation step is a real cost. Every change to your residual model means regenerating code, and the generated artifacts live in your repository. Teams used to editing a Python residual and rerunning a script will find the loop longer. The benefit is runtime speed in C++, so if your problem runs in Python and is fast enough, the generation step is pure overhead.

The C++ story is also split. The pip wheel gives you pre-compiled components but no headers, per the README. Anyone who wants sym::Optimizer in their own C++ target has to build from source with CMake, which pulls in the toolchain the repository's CMakeLists.txt and cmake/ directory expect. That is a heavier commitment than a pip install, and it is the point at which a small team often decides the library is not worth it.

There is also a maturity signal worth reading carefully. The pyproject.toml classifier says Development Status :: 4 - Beta. The project is not archived and the last push was on 2026-08-27, with v0.12.0 released on 2026-08-19. So it is being worked on, but the maintainers themselves label it beta. Treat the API as something that can move between minor versions. The README does not document a deprecation or migration policy for generated code, so if you generate and check in artifacts, plan to regenerate them on upgrade.

SymForce compared with GTSAM and Ceres Solver

The closest comparison is GTSAM, another factor-graph library aimed at robotics and SLAM. The difference is where the derivatives come from. GTSAM ships hand-written analytic Jacobians for its built-in factors and relies on numerical or automatic differentiation for custom ones. SymForce's approach is to derive the Jacobian symbolically from your expression and generate code for it. If your residual is a standard one that already exists in GTSAM, GTSAM is less work. If your residual is unusual, SymForce's symbolic derivation is the part that saves you.

Ceres Solver occupies a different position. It is a general nonlinear least squares library with automatic differentiation and a large ecosystem of cost functions, but it has no symbolic layer and no code generator. You bring the derivatives or you let autodiff handle them at runtime. SymForce's README explicitly frames its sparsity and flattening strategies as an alternative to standard autodiff, and the generated code is branchless with the goal of zero dynamic memory allocation in the templated Eigen output. That is a deployment argument, not a modeling argument. If you are running on a desktop and autodiff is fast enough, Ceres is the simpler dependency.

The honest summary is that SymForce is the most involved of the three to set up and the most rewarding when the derivative is the hard part and the target is an embedded or real-time C++ runtime.

Licence, maintenance and what an upgrade costs

SymForce is Apache-2.0, stated in the README badge and in the pyproject.toml licence field. Apache-2.0 is permissive and includes an explicit patent grant, which matters for a library that may end up in a commercial robotics product. That is a description of the licence text, not legal advice; if your organisation has a policy on patent clauses or attribution in binary distributions, run it past whoever handles that.

The project is developed and maintained by Skydio and, per the README, is used in production for SLAM, bundle adjustment, calibration and sparse nonlinear MPC. That is a statement about the maintainer's own use, not a guarantee for yours. The repository is not archived and the last push was on 2026-08-27. Release cadence over the visible window is roughly two to three months between v0.10.1, v0.11.0 and v0.12.0.

Upgrade cost concentrates in two places. First, generated artifacts. Because the generator emits code you keep, a minor version bump can change the emitted output and you will want to regenerate and diff. Second, the C++ build. Building from source means tracking the repository's CMake configuration, and the Makefile in the repository is explicit that it plays no part in the build process: it is development tooling for formatting and type checks, with CMake doing the actual build. Do not confuse the two when wiring up CI.

Editorial conclusion

Adopt SymForce if you are writing state estimation, bundle adjustment or calibration code and want derivatives generated rather than hand-derived, and if your team can absorb a CMake dependency for the C++ side. Do not adopt it if you need a pure Python runtime with no code generation step, or if your problem has no Lie group structure to exploit. Before committing, verify that pip install symforce gives you the pre-compiled components you need on your platform, and check whether your target deployment requires the C++ headers, which the README says are not included in the wheels and require building from source.

Frequently asked questions

Does pip install symforce include the C++ headers?

No. The README states that the pip install provides pre-compiled C++ components on Linux and Mac but does not include C++ headers. To compile against C++ SymForce types such as sym::Optimizer, you need to build from source.

What is a SymForce symbol?

It is a symbolic variable created through the augmented SymPy API in symforce.symbolic, such as sf.V2.symbolic("L") for a 2D landmark or sf.Rot2.symbolic("R") for a rotation. You build expressions from these symbols, then differentiate or generate code from them.

Is SymForce stable enough for production robotics?

The pyproject.toml classifier lists Development Status :: 4 - Beta, so the maintainers label it beta. The README says Skydio uses it in production for SLAM, bundle adjustment, calibration and sparse nonlinear MPC, which is the maintainer's own usage rather than a compatibility guarantee.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. README
  4. Releases
  5. symforce-org/symforce on GitHub
Community notes

Community notes