Cookiecutter Data Science v2: A Template That Decides Where Your Data Lives
A logical, reasonably standardized, but flexible project structure for doing and sharing data science work.
At a glance
- What is it?
- CCDS v2 is a Python CLI that scaffolds a data science project with fixed directories for raw, interim and processed data, a Makefile, and a small source module. It is a strong fit for solo analysts and small teams who want the same layout every time, and a poor fit for anyone who needs a monorepo or a non-Python stack.
- Who is it for?
- Adopt CCDS v2 if you start Python analysis projects often and want a directory contract that new collaborators can read in a minute. Do not adopt it if your work lives in a monorepo, if your team has already settled on a different layout, or if your pipeline is defined in a tool like DVC or Snakemake that expects to own the data directories.
- Can I use it commercially?
- Yes. MIT 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 39 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 problem CCDS solves is directory drift, not modelling
Every data science project begins with the same small argument: where does the raw file go, and where does the cleaned version go. Left alone, each project answers differently. One repository has data/raw and data/clean, the next has inputs/ and outputs/, a third has everything in notebooks/. Six months later nobody can tell which CSV is the original and which one was overwritten in place. CCDS is a response to that specific failure. It is a cookiecutter template, meaning a parameterised project skeleton, plus a Python package that wraps the cookiecutter utility behind a single ccds command. The README describes it as a logical, reasonably standardized but flexible project structure for doing and sharing data science work. The audience is the person who starts new analysis repositories regularly and wants the first hour to be mechanical rather than a design discussion. It is not a modelling library, not a pipeline runner, and not a data versioning system. It only decides where files live and gives you a few convenience commands to move between stages.
What the generated tree actually separates
The directory listing in the README is the whole product, so it is worth reading closely. Under data/ there are four siblings: external for data from third party sources, interim for data that has been transformed, processed for the final canonical data sets used for modelling, and raw for the original immutable data dump. The word immutable is doing real work there. The convention is that nothing writes back into data/raw, so you can always regenerate everything downstream. Alongside data/ sit models for trained and serialized models, notebooks for Jupyter files, references for data dictionaries and manuals, reports with a figures subdirectory for generated analysis and graphics, and docs, which the README says is a default mkdocs project. Source code goes into a module directory named after the module_name template variable, containing config.py for variables and configuration, dataset.py for scripts that download or generate data, features.py for feature creation, plots.py for visualizations, and a modeling package with train.py and predict.py. That split between dataset, features, modeling and plots is the opinionated part. It pushes you toward named stages rather than one long script, without forcing a framework on you. The notebook naming convention is also specified: a number for ordering, the creator's initials, and a short hyphen-delimited description, with 1.0-jqp-initial-data-exploration given as the example.
Installation and the first command
CCDS v2 requires Python 3.9 or newer. The README recommends pipx because this is a cross-project utility, which is a reasonable call: you do not want the scaffolder inside the virtual environment of the project it just created. The commands given are pipx install cookiecutter-data-science, or pip install cookiecutter-data-science, with a conda-forge option listed as coming soon in the README. Once installed, you start a project by running ccds with no arguments and answering the prompts. The README is explicit that v2 changed from v1: it now requires the new cookiecutter-data-science Python package, which extends cookiecutter, and you use the ccds command-line program instead of cookiecutter. This matters for anyone following older tutorials, where the invocation is cookiecutter followed by the GitHub URL. That older form still works only if you deliberately target v1, using either ccds https://github.com/drivendataorg/cookiecutter-data-science -c v1 or cookiecutter https://github.com/drivendataorg/cookiecutter-data-science -c v1. The resulting tree depends on the settings you choose during the prompts, so the listing in the README is described as something like what you get, not a guaranteed output.
The Makefile is the real interface, and it is only as good as your edits
The generated project includes a Makefile with convenience commands such as make data and make train. The README names those two and does not enumerate the rest, so treat the Makefile as a starting point you are expected to edit rather than a finished build system. This is where the template's value either materialises or does not. A directory tree alone is a filing convention. A Makefile turns it into a reproducible sequence, provided someone keeps the targets current as the code changes. Nothing in the material suggests CCDS enforces that. There is no lockfile step described, no automatic dependency resolution between stages, and no check that data/processed is actually derived from data/raw. The requirements.txt file is described as the requirements file for reproducing the analysis environment, generated with pip freeze, which is a manual snapshot and will drift. The template also ships setup.cfg as the configuration file for flake8 and a pyproject.toml carrying package metadata plus configuration for tools like black. So the linting and formatting opinions are present, but the reproducibility story beyond that is left to you.
Template versioning is tied to the package, which cuts both ways
One design decision deserves attention. By default, ccds uses the project template version matching the installed ccds package version. If you installed ccds 2.0.1, you get the 2.0.1 template. The README explains that the -c or --checkout flag overrides this, taking a branch, tag or commit hash, with ccds -c master given as the example for unreleased changes. The upside is that a given package version produces a predictable skeleton, so two people on the same version get the same starting point. The downside is that upgrading the CLI silently changes what new projects look like. If your team has a house style layered on top of the template, a package upgrade can move the ground under you. The mitigation is to pin the template explicitly with -c for anything that must stay stable, and to check the release notes before bumping. The repository shows releases v2.1.0, v2.2.0 and v2.3.0 between March and July 2025, so the cadence is active enough that this is not a theoretical concern.
Where CCDS is the wrong tool
The template assumes one repository equals one project. If your organisation keeps several related analyses in a monorepo, or if a single deliverable spans a Python model and a separate service, the fixed top-level layout becomes an obstacle rather than a convenience. The data/raw, data/interim, data/processed ladder also assumes you own those directories. Teams already running DVC or Snakemake typically let the pipeline tool declare its own stage outputs, and a second, differently named convention layered on top creates ambiguity about which one is authoritative. The template is Python-first: pyproject.toml, setup.cfg, flake8, black, and a Python module named by module_name. If your work is R, Julia or a mix, the source layout does not map cleanly and you would be deleting more than you keep. Finally, the immutability of data/raw is a convention, not a control. Nothing in the material indicates the template prevents a script from writing into that directory, so the guarantee rests on discipline and code review. Treat it as a norm you enforce, not a property the tool provides.
The alternative: plain cookiecutter or a pipeline framework
The obvious alternative is cookiecutter itself with a template you write or fork. The difference is in who maintains the opinions. Plain cookiecutter gives you templating and nothing else: you supply the directory names, the prompts and the generated files, and you own their upkeep. CCDS ships a maintained set of opinions, a Python package that wraps the utility, and a ccds entry point, so you get the layout without writing it. The trade is that you inherit someone else's stage names and directory vocabulary, and you follow their release cadence. The other alternative is a pipeline framework such as DVC or Snakemake, which addresses a different layer. Those tools track what was produced from what, and can decide when a stage is stale. CCDS does not do any of that; it only arranges where the artifacts sit. The two are not mutually exclusive, but combining them means agreeing which system names your stages, and the README does not describe an integration path, so that reconciliation is on you.
Licence and the cost of keeping up
CCDS is MIT licensed, which is permissive and places few obligations on how you use the generated structure in your own repositories. Note that the LICENSE file in a generated project is described as the open-source license if one is chosen during the prompts, so the licence of your project is a separate decision from the licence of the template. This is not legal advice; check the terms against your own situation. On maintenance, the ongoing cost is small but not zero. The CLI is a cross-project tool, so upgrades are a deliberate act rather than something that happens when a project's dependencies resolve. Each upgrade changes the template that new projects receive, which means the cost lands on the next project rather than the current one. The practical approach is to install once with pipx, decide on a version, and revisit it when you actually start something new. Because the template version follows the package version, that decision is explicit rather than automatic.
Editorial conclusion
Adopt CCDS v2 if you start Python analysis projects often and want a directory contract that new collaborators can read in a minute. Do not adopt it if your work lives in a monorepo, if your team has already settled on a different layout, or if your pipeline is defined in a tool like DVC or Snakemake that expects to own the data directories. Before you commit, run ccds once with the options you intend to use, inspect the generated Makefile and pyproject.toml, and confirm the module name it produces matches what you will import in your own scripts. The template version is pinned to the installed package version, so decide early whether you will track the package or pin with ccds -c.
Community notes