Library / SDK
Nixtla/mlforecast avatar
Nixtla/mlforecast

mlforecast: Fitting Millions of Series Through a scikit-learn Interface

Scalable machine 🤖 learning for time series forecasting.

1,277 stars133 forksPythonApache-2.0

At a glance

What is it?
Nixtla's mlforecast turns lag and date feature engineering into a preprocessing step that any scikit-learn regressor can consume, with optional Dask, Ray or Spark execution. The design is coherent, but the library is a feature pipeline plus a training loop, not a modelling system, and the documentation leaves several operational questions open.
Who is it for?
Adopt mlforecast if you already have a regressor you trust and your real problem is generating lag, rolling and date features across thousands of series without writing that pipeline yourself. Do not adopt it if you need a model that understands seasonality and trend on its own, or if you expect the library to choose hyperparameters or validate your splits for you.
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 1 day 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 gap mlforecast is built to fill

The README states the motivation plainly: existing Python options for machine learning forecasting are described as slow, inaccurate and poorly suited to scale, and mlforecast is presented as a library for production forecasting that can fit millions of time series. That framing tells you who the intended user is. It is not someone who wants a forecasting model. It is someone who already has a model, typically a gradient boosted tree, and has discovered that the expensive part of the job is not the regressor but the feature matrix in front of it. Building lag features, rolling means and calendar attributes for a single series is a few lines of pandas. Doing it for fifty thousand series, without accidentally leaking future values into past rows, and doing it again identically at prediction time, is where most in-house pipelines break. mlforecast exists to own that step. The README also notes that each model is trained on all series, which is the central design decision: this is a global model library, not a per-series fitting library. If your series are few and long, or genuinely unrelated to each other, that decision works against you.

What the MLForecast object actually does

The documented flow has three parts. You supply a long-format dataframe with a unique_id column identifying each series, a ds column for the timestamp and a y column for the target. You supply a list of models, each of which must follow the scikit-learn API. You then instantiate MLForecast with those models plus a specification of the features you want, described in the README as lags, transformations on the lags and date features. The README also mentions transformations applied to the target before fitting, which are restored at prediction time, so a log or difference transform is handled inside the object rather than by you. The sample generation helper, generate_daily_series, produces exactly that shape, and the README's table shows static_0 carried alongside each row, which is how static covariates reach the model. The important structural point is that MLForecast is stateful. It holds the feature configuration and the fitted models together, so the same object that produced the training matrix produces the prediction matrix. That is what prevents train and predict skew, and it is the main reason to use the library rather than assembling features yourself. The README gives a short example beginning with from mlforecast import MLForecast and from mlforecast.lag_transforms import ExpandingMe, which indicates that lag transformations are separate importable classes rather than strings or lambdas. The documentation does not, in the material available, enumerate the full set of those transform classes.

Installation and the distributed path

Installation is two commands, one per channel. From PyPI, pip install mlforecast. From conda-forge, conda install -c conda-forge mlforecast. The README points to a separate installation page for more detail, and that page is where any optional dependency groups for Dask, Ray or Spark would be described, since the base install cannot reasonably pull all three. The distributed workflow is documented as a distinct guide titled Distributed Training, which describes using a Dask, Ray or Spark cluster to train models at scale. The README's feature list claims out-of-the-box compatibility with pandas, polars, spark, dask and ray, and there are sample notebooks for both a pandas and a polars m5 evaluation, which suggests the polars path is a supported input format rather than an afterthought. What the material does not show is a single command that turns a local MLForecast into a distributed one. The existence of a separate quick start page for distributed training implies additional configuration, and you should read that page before assuming the transition is a parameter change. The same applies to the cross-validation and hyperparameter optimization guides, which are listed as how-to pages rather than features of the core object.

Where the abstraction stops helping

The most consequential limitation is stated in the README rather than hidden: models must follow the scikit-learn API with fit and predict methods. That excludes a large part of the forecasting world. A model that needs its own loss function over a forecast horizon, or that maintains per-series state, or that expects a sequence rather than a tabular row, does not fit this interface. You can wrap such a model, but the wrapping work is yours. The second limitation is the global training assumption. Every model is trained on all series, so a single dominant series or a cluster of very large series will influence the parameters used for every small series. The README lists transfer learning as a guide, which is the documented answer to relatedness across series, but transfer learning is a different workflow from simply fitting one model per group. Third, the long-format contract requires a unique_id even for a single series, and the README explicitly says to set that column to a constant value in that case. That is a small friction that signals the library is not designed around the single-series case. Finally, the README's claim of the fastest implementations of feature engineering is a claim, not a measurement, and no benchmark is given in the material available. Treat it as the project's position rather than a verified property.

How it compares with a state space library

The natural alternative for a reader arriving at this page is a statistical or state space forecasting library, and the difference in approach is not cosmetic. A state space model such as those in StatsForecast, which is a sibling project from the same organisation and is linked from the README's social badge, represents each series with explicit level, trend and seasonal components and estimates them per series. mlforecast does the opposite. It flattens the series into a supervised learning problem, constructs lag and rolling features, and lets one regressor learn a shared mapping from those features to the target across all series. The consequences follow directly. State space models handle short series and strong local seasonality well because the structure is built in. mlforecast needs enough history per series for the lag features to be informative, and it needs the series to share patterns, because the model has no per-series parameters to fall back on. In exchange, mlforecast accepts arbitrary exogenous variables and static covariates through the same tabular interface, and it scales horizontally through Dask, Ray or Spark, which a per-series estimation loop does not do naturally. The honest framing is that these are complementary, and the README's own guide list, which includes cross-validation and probabilistic forecasting through conformal prediction, describes a workflow that could sit on top of either.

Probabilistic output and what it costs

The README lists probabilistic forecasting with conformal prediction as a feature and links a tutorial titled Prediction Intervals in Forecasting Models. This is worth understanding before you plan around it, because conformal prediction produces intervals by calibration on held-out data rather than by modelling a distribution. That means the intervals are only as good as the calibration split, and they carry a coverage guarantee under exchangeability assumptions that time series often violate. The README does not, in the supplied material, discuss how calibration is performed for the multi-series case or how the intervals behave when the series are drifting. If prediction intervals are central to your use case, the tutorial is the place to look, and you should check whether the coverage you need is something the method can promise for your data. This is not a reason to avoid the library. It is a reason to read the tutorial before you promise intervals to anyone downstream.

Maintenance, licence and versioning

The repository is not archived and the last push is dated 2026-09-10, with releases at v1.1.0 in July 2026, v1.0.31 in March 2026 and v1.0.3 in February 2026. The spacing of those releases, roughly monthly patch releases with a minor version in the middle of the year, is consistent with a project under active maintenance rather than one in a freeze. The jump from v1.0.3 to v1.0.31 within about two weeks suggests a rapid patch cadence, which cuts both ways: fixes arrive quickly, and you should expect to move patch versions to stay current. The project is licensed Apache-2.0, which is a permissive licence that permits commercial use and modification, and it includes an explicit patent grant. That is the standard reading of the licence text, not legal advice, and if you are redistributing the library inside a product you should have your own counsel review the notice and attribution requirements. The README does not describe a deprecation policy or a compatibility guarantee across minor versions, so pinning a version and reading the release notes before upgrading is the prudent path. The upgrade cost itself is hard to estimate from the material available, because the release notes are not included here.

Editorial conclusion

Adopt mlforecast if you already have a regressor you trust and your real problem is generating lag, rolling and date features across thousands of series without writing that pipeline yourself. Do not adopt it if you need a model that understands seasonality and trend on its own, or if you expect the library to choose hyperparameters or validate your splits for you. Before committing, verify three things against your own data: that your series are regularly spaced, because the README's long format of unique_id, ds and y gives no visible mechanism for irregular timestamps; that the regressor you plan to use actually follows the scikit-learn fit and predict contract, since that is the only model interface the documentation describes; and that your preprocessing fits in memory or your cluster is configured, because the distributed path is a separate setup from the local one.

Official sources

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

Community notes