uber/orbit: Bayesian Time Series Forecasting with an initialize-fit-predict API
A Python package for Bayesian forecasting with object-oriented design and probabilistic models under the hood.
At a glance
- What is it?
- Orbit wraps Stan and Pyro sampling behind a scikit-learn-style interface for ETS, LGT, DLT and KTR models. It is a reasonable fit when you need posterior uncertainty on a business time series, and a poor fit when you cannot afford MCMC runtime or a cmdstanpy toolchain.
- Who is it for?
- Adopt Orbit if you need posterior distributions over forecast components on a small number of business series and you can install cmdstanpy in your environment. Do not adopt it if you need a point forecast for thousands of series on a tight latency budget, or if your legal team cannot accept a NOASSERTION licence classifier.
- 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 116 days ago.
- What is it written in?
- Mainly Python, 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 forecasting problem Orbit is aimed at
Most forecasting libraries give you a number. Orbit gives you a distribution over the number, plus distributions over the components that produced it. The README describes the package as providing a familiar initialize-fit-predict interface while using probabilistic programming languages under the hood, and the model list makes the target explicit: Exponential Smoothing, Local Global Trend, Damped Local Trend and Kernel Time-based Regression. These are structural time series models. Each one decomposes a series into level, trend, seasonality and regression terms, and each parameter in that decomposition gets a posterior.
That matters when the forecast feeds a decision with asymmetric costs. Inventory planning, capacity scheduling and budget allocation all need to know how bad the bad case is, not just the central estimate. A model fitted with MCMC returns a sample from the joint posterior, so the prediction interval comes from the model rather than from a residual heuristic bolted on afterwards. The README's quick start loads the ICLaims dataset, a weekly claims series, and fits a DLT with three external regressors and a seasonality of 52. That is the shape of the intended workload: one series, or a modest number of related series, where you care about interpretable components and honest uncertainty.
The audience is therefore narrower than the topic list suggests. If you are forecasting ten thousand SKUs with two years of weekly history each, the per-series sampling cost will dominate everything else, and Orbit is the wrong tool.
What sits under the initialize-fit-predict interface
Orbit is a layer over probabilistic programming runtimes. The README states plainly that the project requires cmdstanpy as one of the core dependencies for Bayesian sampling, and the PyPI topics list both stan and pyro. So the architecture is: a Python model class holds the configuration (response column, date column, regressor columns, seasonality period), the class translates that configuration into a probabilistic model, and the sampling backend does the inference. The user never writes Stan or Pyro code in the basic workflow.
Estimation is exposed as three modes. MCMC is described as a full sampling method. MAP is described as a point estimate method. VI is described as a hybrid-sampling method on an approximate distribution. Those three are not interchangeable, and the choice is the main performance decision you will make. MCMC gives you the posterior you asked for at the cost of runtime. MAP collapses the posterior to its mode, which is fast and gives you no uncertainty. VI approximates the posterior, which is faster than MCMC and less faithful, and the quality of the approximation depends on the model and the data.
The model classes also share a common surface. In the quick start, DLT is constructed with response_col, date_col, regressor_col and seasonality, then fit with a training frame, then predict with a test frame. The fitted object exposes date_col and response_col as attributes, which the plotting helper consumes. That consistency across ETS, LGT, DLT and KTR is the actual product: you learn one workflow and swap the model class.
Installing Orbit and running the DLT example
The README gives three installation paths. From PyPI: pip install orbit-ml. From source: git clone https://github.com/uber/orbit.git, then cd orbit, then pip install -r requirements.txt, then pip install . From conda-forge: conda install -c conda-forge orbit-ml. There is also a dev install, pip install git+https://github.com/uber/orbit.git@dev, and the README warns that the repository's default page is the dev branch. If you want the stable version, the README points you at the master branch. That warning is worth taking literally: cloning the repository without checking out master gives you dev code.
The quick start itself is short. It imports load_iclaims from orbit.utils.dataset, DLT from orbit.models, and plot_predicted_data from orbit.diagnostics.plot. It loads the frame, splits off the last 52 rows as a test set, constructs DLT with response_col set to claims, date_col set to week, regressor_col set to the list ['trend.unemploy', 'trend.filling', 'trend.job'], and seasonality set to 52. Then dlt.fit(df=train_df), then predicted_df = dlt.predict(df=test_df), then a plotting call that takes the training frame, the predicted frame, the date column, the actual column and the test frame.
Two things in that snippet are easy to miss. First, the data is described in a comment as log-transformed, so the loader is doing preprocessing that affects how you read the output. Second, the regressor column names use a dot convention, trend.unemploy, which is a naming scheme rather than a nested accessor. If you bring your own frame, you supply your own column names and the same keys. The README does not show a config file; configuration is constructor arguments. There is no YAML to edit, which is simpler, and also means there is no artifact describing how a saved model was configured beyond whatever you serialize yourself.
Where Orbit is the wrong choice
The first limitation is stated by the project itself. The disclaimer says Orbit is stable and being incubated for long-term support, and that it may contain new experimental code for which APIs are subject to change. That is an explicit warning against pinning your production pipeline to an unversioned install. Treat the version number as load-bearing.
The second limitation is the dependency. cmdstanpy is a core dependency for Bayesian sampling, which means a working Stan toolchain in your environment. That is not a pure-Python install. In containerized or serverless deployment, a compiled toolchain is a real constraint, and the README does not describe a pure-Python fallback for the sampling path. MAP avoids sampling, but MAP is a point estimate, so you lose the reason you picked Orbit.
The third limitation is the workload shape. The supported models are structural and univariate in the framing shown. The quick start fits one series with three regressors. Nothing in the supplied material describes a global model fitted across many series with shared parameters, which is how libraries aimed at large panels usually work. If your problem is cross-series learning, Orbit's per-series fit is a mismatch.
The fourth is the release cadence visible in the release list. Three recent releases span v1.1.4.9 in April 2024, v1.1.5.0 in March 2026 and v1.1.5.1 in May 2026. That is a long quiet stretch followed by two patch-level releases. The version numbering stays in the 1.1.5 patch range across those two 2026 releases, which suggests maintenance rather than feature expansion. Plan for a project that is looked after, not one that is growing quickly.
How Orbit differs from statsmodels and Prophet
The closest conventional alternative is statsmodels, which also ships exponential smoothing and ARIMA style models in Python. The difference is the inference layer. statsmodels fits by maximum likelihood and gives you parameter estimates with standard errors under asymptotic assumptions. Orbit fits by sampling from a posterior, and the README's sampling list is the whole point of the package. If you want a coefficient table and a confidence interval derived from a likelihood, statsmodels is the shorter path. If you want a predictive distribution that reflects the full uncertainty in level, trend and seasonality jointly, Orbit is doing something statsmodels does not do in the same way.
Prophet is the other obvious comparison, and the contrast is sharper. Prophet is a single additive model with a fixed structure, fitted by a backfitting procedure, and it is designed to be run across many series with minimal tuning. Orbit exposes four model classes and lets you choose the estimation method, which means more control and more decisions. Prophet's intervals come from a simulation procedure over trend and noise. Orbit's come from the sampler. Neither is automatically better; they fail differently. Prophet is easier to run at scale and harder to reason about component-wise. Orbit is the reverse.
The honest summary is that Orbit occupies the middle: more structured than a generic regression, less automated than Prophet, and more explicit about uncertainty than either. If you have already decided you need a Bayesian structural model, the remaining question is whether Orbit's four model classes cover your case, and the README does not claim they cover everything.
Maintenance, versioning and the licence question
The repository documents versions and changes in docs/changelog.rst, which is where you should look before upgrading. The README also links a contributing guide and a code of conduct, and the project runs a build and test workflow on GitHub Actions, referenced by the badge pointing at .github/workflows/test.yaml. That is a normal open source maintenance posture.
The upgrade cost is concentrated in two places. First, the API stability caveat in the disclaimer, which applies to experimental code specifically. Second, the cmdstanpy dependency, since a Stan upgrade can change compilation behaviour independently of Orbit's own version. Pinning Orbit without pinning cmdstanpy leaves half the stack floating.
The licence is the item that needs your own review. The repository metadata reports NOASSERTION, which means an automated classifier could not map the LICENSE file to a standard identifier. The README's badge links to the LICENSE file on the master branch, and the PyPI badge reports a licence, but the machine-readable field is unresolved. That is not a statement that the licence is restrictive or permissive; it is a statement that you cannot rely on the classifier. Read the LICENSE file yourself and route it to whoever handles this at your organization. Nothing here should be read as legal advice.
One more practical note: the README's user notice says the default page of the repository is the dev branch. Anyone who clones without reading that will get development code and may not realize it.
Editorial conclusion
Adopt Orbit if you need posterior distributions over forecast components on a small number of business series and you can install cmdstanpy in your environment. Do not adopt it if you need a point forecast for thousands of series on a tight latency budget, or if your legal team cannot accept a NOASSERTION licence classifier. Before committing, run the DLT quick start from the README on your own data with MCMC, time the fit, and check whether MAP or VI gives you an acceptable interval width. Orbit is not a drop-in replacement for a gradient-boosted forecaster on wide panels of short series, and the repository itself warns that APIs may change.
Community notes