How do I distinguish between development dependencies and production dependencies?

← Getting Started · Ref: Q10

EK9 separates dependencies into two groups inside `defines package`:

`deps` - production dependencies:

  deps <- {
    "ekopen.network.utils": "1.6.1-9"
  }
  These are required at runtime. When someone depends on YOUR package, they also get your `deps` as transitive dependencies. These are included in packaged artifacts (-P).

`devDeps` - development-only dependencies:

  devDeps <- {
    "ekopen.test.helpers": "2.0.0-0"
  }
  These are only available during development and testing. They are NOT included when your package is deployed or when others depend on your package. Test frameworks, mock libraries, and development tools belong here.

Key differences:
- `deps` are transitive: your consumers inherit them
- `devDeps` are NOT transitive: your consumers never see them
- `deps` are included in -P (package) and -D (deploy)
- `devDeps` are excluded from packaged artifacts
- `deps` are resolved by -Dp for everyone
- `devDeps` are only resolved for the package owner

Rule of thumb:
- If your code needs it to RUN: put it in `deps`
- If your code only needs it to TEST or BUILD: put it in `devDeps`

Both use the same Dict literal syntax with module name to version mapping.

The code example below shows a package with both production and development dependencies clearly separated.

See Q7 for managing dependencies. See Q11 for excluding transitive dependencies.

Example

defines module qa.getting.started.dev.vs.production.deps

  defines package

    version as Version: 1.0.0-0
    description as String = "Shows deps vs devDeps separation"
    license <- "MIT"
    publicAccess <- true

    tags <- [
      "example"
    ]

    applyStandardIncludes <- true

    //Production dependencies: included in deployed package
    deps <- {
      "ekopen.network.support.utils": "1.6.1-9",
      "ekopen.net.handy.tools": "3.2.1-0"
    }

    //Development-only: test frameworks, mocks, tools
    devDeps <- {
      "ekopen.org.supertools.util": "4.6.1-6",
      "ekopen.org.net.tools.misc": "3.2.3-21"
    }

  defines program
    DevVsProductionDeps()
      stdout <- Stdout()

      stdout.println("deps: included in production, transitive to consumers")
      stdout.println("devDeps: development only, never shipped to consumers")

Common mistakes

E01040 — Defining two constructs with the same name in the same module triggers E01040 — duplicate construct. Each program name must be unique within the module. See ek9 -h E01040 for details.

Incorrect:

defines program
    DevVsProductionDeps()
      stdout <- Stdout()
    DevVsProductionDeps()
      stdout <- Stdout()

Correct:

defines program
    DevVsProductionDeps()
      stdout <- Stdout()
Other ways to ask this
  • What is the difference between deps and devDeps?
  • How do I add test-only dependencies?
  • What are development dependencies in EK9?
  • How do I keep test libraries out of production?
  • What is the EK9 equivalent of Maven scope=test or Gradle testImplementation?
  • I use npm devDependencies, how does EK9 separate dev from production?

Coming from another language?

Python: pip has no built-in distinction (extras_require for dev). Java: Maven scope=test or Gradle testImplementation. Rust: Cargo.toml [dev-dependencies]. npm: package.json devDependencies. Go: no formal distinction. EK9 uses deps and devDeps as parallel Dict literals in the source file.

Keywords: start, development, package, gradle, production, npm, test, beginner, deps, maven, intro, first, testImplementation, transitive, dependencies, scope, devDeps, devDependencies, deploy