Julia standards (reference: August 2026)
Criteria verified as of August 2026. Re-verify on the web before committing to anything (§8).
1. Scope and triggers
Applies to all Julia work: packages, numerical code, environments, tests, packaging and deployment.
Triggers: .jl, Project.toml, Manifest.toml, .JuliaFormatter.toml, test/runtests.jl, juliaup,
Threads.@spawn, @code_warntype, ccall, PythonCall.
The two axes of this skill. (1) Multiple dispatch is the language: it is not sugar over OOP,
it is the mechanism of composition and extension, and almost every design error in Julia is a dispatch
design error (badly cut type hierarchies, type piracy, methods that are too specific or too lax).
(2) Latency ("time to first plot") is the language's historical objection and there is a great deal
of expired information about it: the problem is not solved, it is bounded — the native code cache
arrived in 1.9, not in the recent versions, and current work is on trimming and standalone
binaries. Any claim about latency is verified against the version you are going to use, not against a
2022 blog post.
Not applicable: see mlops-standards (the model lifecycle is theirs: model registry and
versioning, feature store, serving, drift monitoring, retraining, train/serve skew —
how the Julia that trains or scores is written belongs here), data-engineering-standards
(ingestion, orchestration, idempotency, backfill, Parquet, freshness SLA: the platform is theirs; the
computation code that consumes it belongs here), analytics-bi-standards (the dashboard and who
decides with it; the code that produces the figures, here), data-warehouse-modeling-standards (the
shape of the analytical model), lakehouse-standards (table format and catalogue),
sql-standards (the SQL you write via DBInterface/LibPQ is subject to their criteria),
python-standards (§7 sets when the right answer is Python), r-standards (statistics and
communication of results; see §7), gpu-computing-standards (the GPU as a resource that is
provisioned, shared, monitored and paid for: driver, CUDA, MIG, quotas, cost; the kernel and the
CUDA.jl/KernelAbstractions.jl code that uses it belongs here), llm-app-engineering-standards
and rag-standards (the AI application layer), ai-governance-standards (governance and compliance),
c-standards/cpp-standards (the native code on the other side of a ccall: memory, UB,
sanitizers, ABI; the boundary from Julia —ccall, Ptr, GC.@preserve, unsafe_*, JLL— belongs
here), fortran-standards (the Fortran kernel on the other side of a ccall: bind(c),
contiguity, index order, parallelism model and compiler flags are theirs; the boundary from Julia
belongs here), cicd-standards (the pipeline that runs the gates of §4), kubernetes-standards
(image and deployment), appsec-standards (agnostic threat modelling; here only the Julia sinks),
vulnerability-management-standards (triage and finding SLA; here only the state of scanning),
secrets-management-standards, observability-standards (OTel/Prometheus pipeline; here only the
instrumentation in the code), api-design-standards (the contract of an HTTP service in Julia:
resources, codes, pagination, versioning).
2. Default decisions / Toolchain
Verify the latest version on the web before pinning it in a real project (§8).
| Piece |
Choice |
Verified as of Aug 2026 |
Why |
| Runtime (production) |
LTS unless there is a concrete need |
1.10.11 (2026-03-09) is the current LTS |
Julia supports each minor only until the next one ships: 1.11 is already EOL. Without LTS, "stable" implies an upgrade every ~4-5 months |
| Runtime (features/performance) |
Current stable |
1.12.6 (2026-04-09) |
1.12 will expire when 1.13 ships. 1.13 is not final as of Aug 2026 (rc2 on 2026-07-29); master is already 1.14-dev |
| Installer/versions |
juliaup with the lts and release channels |
1.20.9 (2026-07-28) |
Never the Julia from the distro's package manager |
| Environments |
Pkg + Project.toml per project |
— |
One environment per project; never install into the global @v1.x environment |
| Reproducibility |
Manifest.toml versioned in applications |
— |
See §3: in packages the Manifest.toml is NOT versioned |
| Formatting |
JuliaFormatter with .JuliaFormatter.toml |
2.12.4 (2026-07-31) |
Very high release cadence: pin exactly or CI breaks on its own |
| Static analysis |
JET.jl |
0.12.0 (2026-07-28) |
Pre-1.0 and coupled to compiler internals: the JET version depends on the Julia one |
| Package quality |
Aqua.jl |
0.8.16 (2026-06-05) |
Detects type piracy, method ambiguities, broken exports, unused deps, incomplete [compat] |
| Tests |
Test (stdlib) |
— |
Sufficient; TestItems/ReTest only if the ergonomics justify it |
| Benchmarks |
BenchmarkTools.jl (@benchmark, @btime) |
— |
A bare @time measures compilation on the first call: it is useless for measuring |
| Documentation |
Documenter.jl |
1.17.0 (2026-02-20) |
Doctests in CI |
| Standalone binary |
PackageCompiler.jl (sysimage) / juliac+--trim (executable) |
PackageCompiler 2.4.0 (2026-06-10) |
--trim is experimental (1.12+) and requires --experimental; it requires the absence of reachable dynamic dispatch |
| Python interop |
PythonCall.jl in new code |
— |
PyCall.jl is in maintenance mode; PythonCall isolates the environment with CondaPkg and is type-stable by default |
| R interop |
RCall.jl |
— |
— |
Version criteria: if the service has an SLA and you are not going to dedicate an upgrade window
every 4-5 months, LTS. If you need trimming, the threading improvements or a package that only
supports 1.12+, stable — assuming the upgrade to 1.13 as soon as it ships. Do not mix: the Julia
version is pinned in [compat] and in CI, and the same number runs locally, in CI and in production.
3. Structure and conventions
MiPaquete/
Project.toml # name, uuid, version, [deps], [compat] MANDATORY
Manifest.toml # package: .gitignore | application/service: versioned
src/MiPaquete.jl # root module; includes and exports
test/runtests.jl # + its own Project.toml in test/
docs/ # Documenter
ext/ # package extensions (weak deps)
Manifest.toml: the most frequently broken rule. In an application (service, pipeline,
analysis that must be reproducible) it is always versioned: it is the lockfile, and without it
Pkg.instantiate() resolves different versions every day. In a publishable library it is not
versioned: it would pin your consumers' dependency tree. A library's reproducibility comes from
[compat], not from the manifest. Deployment: Pkg.instantiate() over the versioned manifest, never
Pkg.update().
[compat] is mandatory for every dependency and for julia. Without it, the General registry
does not even accept the package, and a [compat] with an open upper bound turns anyone else's
release into your failure. Use SemVer bounds ("1", "0.8.3"), not ">=x".
- Registry: General by default; a private registry (
LocalRegistry) for internal code. Never
Pkg.add(url=...) to a branch in production — either it comes in through a registry, or it is pinned
by commit in the manifest.
- Names: types
UpperCamelCase, functions and variables lowercase/snake_case without underscores
if it still reads well, constants UPPER; a ! suffix on every function that mutates its
arguments (and the mutated argument goes first). Modules = the package name.
- Minimal exports: export what is API, the rest is accessed qualified. Everything exported is
documented and enters SemVer.
- Files per concept, not a
utils.jl; include() only from the root module, in explicit order.
Types and dispatch — the hard rules:
- Design generic functions with methods, not hierarchies. Abstract types define interfaces (which
methods must exist), and that interface is documented: Julia does not verify it for you.
- Annotate the field types of a
struct, always. An ::Any field (or a non-concrete parametric
type) destroys the performance of everything that touches the object. Use type parameters
(struct Punto{T<:Real}) instead of abstract fields.
struct immutable by default; mutable struct only when the state has to change.
- Annotating the types of the arguments does not speed anything up: it is for dispatch and for
documenting the contract. Be as generic as you can (
AbstractVector{<:Real}, not Vector{Float64}),
unless you want to restrict deliberately.
Union{} and Any in an inference are a symptom: Union{} as a return type means "this always
throws"; Any means the compiler gave up. Both show up in @code_warntype.
Type piracy: a serious antipattern. The manual's definition: "«Type piracy» refers to the practice
of extending or redefining methods in Base or other packages on types that you have not defined." If
neither the function nor any of the method's types are yours, you are pirating: you change the
behaviour of someone else's code globally and invisibly, and the result can range from a remote and
untraceable bug to, in extreme cases, taking Julia down. Alternatives: define your own wrapper type,
your own function, or use a struct with the desired behaviour. Aqua.jl detects it — make that
test block the merge.
Error style: your own typed exceptions (struct MiError <: Exception) with showerror;
Base's ArgumentError/DomainError/BoundsError when they fit. @assert is for internal invariants
and can disappear with --check-bounds=no/optimisations: do not use it to validate input. No empty
catch e end; try/finally (or the do-block patterns) to release resources.
4. Quality: formatting, analysis, tests
- Formatting:
JuliaFormatter with a versioned .JuliaFormatter.toml, checked in CI. Pin the
version exactly in the CI environment: it publishes several versions a week and a style change
breaks the gate without anyone having touched the code.
- Static analysis:
JET.jl (report_package) over the package. Realistically: JET is pre-1.0
and depends on compiler internals, so a Julia upgrade can change its findings. Introduce it as an
informative job first and turn it into a gate when the baseline is clean; never leave its version
floating.
Aqua.jl as a gate: Aqua.test_all(MiPaquete) in runtests.jl. It covers what no human review
catches: type piracy, method ambiguities, incomplete [compat], declared and unused deps, exports
that do not exist.
- Tests (
Test stdlib):
@testsets nested per unit of behaviour; one failure reason per test.
- Mandatory edges: empty collection, one element,
NaN/Inf/-0.0, integer overflow (Int in
Julia wraps silently, it does not promote), singular matrix, unexpected type, missing
propagating, out-of-range indices.
- Floating point numbers:
≈ (isapprox) with explicit atol/rtol, never ==.
@inferred over the hot path functions: it turns "this was type-stable" into a test that fails
when somebody breaks it. It is the most valuable test in a Julia package.
Random: an explicit seed per test (StableRNGs if the result must be identical across Julia
versions — the Random RNG stream can change between minors).
- Every fixed bug leaves a regression test. Flaky = fixed or deleted.
- CI gates (they block the merge, cheapest first):
JuliaFormatter in check mode (pinned version).
- Reproducible
Pkg.instantiate() + Aqua.test_all.
Pkg.test() with coverage (Coverage.jl/Codecov); agreed threshold, coverage is a signal.
@inferred / performance regression benchmarks on the critical paths.
JET.jl (informative → gate) and Documenter doctests.
- Dependency audit (§5) and artifact build.
- CI matrix: LTS + stable +
nightly (the last one allowed to fail). If you support both lines,
both are tested — saying so in the README without testing it is lying.
5. Stack security
Serialization (serialize/deserialize): it is neither an interchange format nor safe.
Official documentation: "deserialize assumes the binary data read from stream is correct and has
been serialized by a compatible implementation of serialize. deserialize is designed for
simplicity and performance, and so does not validate the data read. Malformed data can result in
process termination." In addition, "The data format can change in minor (1.x) Julia releases" and
the word size (32/64 bits) of the reading and the writing machine must match. Rules:
FORBIDDEN to deserialise untrusted input; FORBIDDEN to use Serialization as a persistence
format across versions or across machines. For data: JLD2, Arrow, Parquet, JSON or a versioned format
of your own, always validated on read.
eval and metaprogramming: @eval/eval over strings built with user input, and Meta.parse
of input, are arbitrary code execution: FORBIDDEN. In addition, eval at runtime invalidates
compiled code and causes recompilation (latency cost). Macros are for syntactic transformation at
compile time; if a macro can be a function, it is a function. include() of paths built with input:
forbidden.
ccall and unsafe_*: ccall is a total trust boundary — a signature error is memory
corruption, not an exception. Rules: signatures verified against the real header, GC.@preserve
around any pointer to Julia-managed memory that crosses the boundary, and
unsafe_load/unsafe_wrap/unsafe_store! only with verified length and ownership. Third-party
binaries: JLL packages from the ecosystem (BinaryBuilder), never .so files downloaded by hand.
@inbounds and @simd are unsafe by construction. @inbounds removes the bounds check:
with a wrong index you read or write outside the array — silent memory corruption, not a
BoundsError. @simd promises the compiler that the iterations are independent and that it may
reorder the operations (including floating point arithmetic, so the numerical result can change).
Criteria: only after measuring that they help, only in loops whose indices are provably correct by
construction, with a test covering the extremes, and never over indices derived from external input.
--check-bounds=no globally: FORBIDDEN in production.
- Dependency auditing: the ecosystem is immature and that has to be said. As of Aug 2026 there is
no
Pkg.audit in Pkg (it is still an open proposal). What does exist: the Julia Security Advisory
Database (SecurityAdvisories.jl), with advisories identified as JLSEC-YYYY-nnn in an
OSV-compatible format, and the Security Working Group created in 2025-11. Practice today:
consume those advisories from an OSV-compatible scanner over the Manifest.toml, and assume
partial coverage — in particular that of the >1,500 JLL packages, which repackage third-party
binaries whose CVEs are not automatically mapped to the JLL name. This is the ecosystem's largest
risk surface and today it is not reliably covered. Do not invent a tool that does not exist;
declare the gap (§8).
- SQL / commands: parameterised queries via
DBInterface.execute(stmt, params); interpolating input
into SQL is an absolute veto. Cmd backticks (run(cmd $arg)) do not go through a shell and
that protects from shell injection — but run(sh -c $x) is injection. Never build a Cmd from a
string with input.
- Secrets: environment variables or a manager; never in
Project.toml, in the code, in
LocalPreferences.toml or in exported Pluto notebooks. Careful with the output of @show/dump
over config structures.
- HTTP services: validate and limit the body size, timeouts on every outbound call, and do not
return stack traces to the client — a Julia trace exposes internal paths and package names.
- Containers: an image based on the official
julia:<version> with an exact version, non-root,
multi-stage. The image is large — the precompiled package depot (~/.julia) weighs a fair
amount and the PackageCompiler sysimage adds hundreds of MB. Precompile in the build
(Pkg.precompile()), never at container start-up, and discard the compiler and the build sources in
the final stage.
6. Performance and operability
Type stability is performance criterion number one. If the compiler can infer a concrete type for
each value, it generates specialised code comparable to C; if not, it falls back to dynamic dispatch
and allocations, and you lose one or two orders of magnitude. Protocol, in this order:
@code_warntype over the function: anything in red (Any, a wide Union{...}) is the bug.
@inferred in the test so it does not come back.
@allocated/@benchmark: in a well-written numerical loop, allocations tend to zero.
Unexpected allocations = type instability or accidental copies.
Profile/ProfileView to locate; never optimise without having measured.
Concrete silent killers:
- Untyped global variables: a global without
const can change type, so the compiler infers
nothing from it and all its use becomes dynamic. Rule: the work goes inside functions, with the
data as arguments; the globals you do need are declared const (or with a type annotation). A
top-level script with a heavy loop is the slowest possible pattern.
- Containers with an abstract type:
Vector{Any}, Dict{String,Any}, or a struct with Any fields.
- Functions that return different types depending on a branch.
- Closures that capture variables whose type changes.
Memory and allocations:
@views / view instead of copies when slicing arrays (A[:, 1] copies). In hot loops, the
difference is everything.
- Broadcasting with
. fuses into a single loop with no temporaries (@. so as not to forget a
dot); chaining operations without . creates one temporary array per operation.
- Preallocate and use the
! variants (mul!, map!, sort!) on the hot path.
- Arrays with a concrete element type and
StaticArrays for small fixed-size vectors.
Latency (TTFX) — real state, no folklore: the native code cache has existed since Julia 1.9
(package images); in exchange, precompilation is slower and the caches larger. There is still latency
on the first execution of uncached code. Tools in order of cost: (a) precompile in the image build;
(b) precompilation workloads in the package itself (PrecompileTools); (c) a sysimage with
PackageCompiler; (d) a standalone executable with juliac --trim (experimental, 1.12+, requires
--experimental and fails if there is dynamic dispatch reachable from the entry point — that is,
it demands strictly inferable code). For CLIs and short, frequent functions, latency is still an
argument against Julia (§7).
Parallelism:
- Threads for shared memory:
Threads.@spawn + fetch, Threads.@threads for homogeneous loops.
Since 1.12 there is by default 1 interactive thread in addition to the worker one (-t1,1),
and Threads.@spawn :samepool to avoid jumping threadpool. --gcthreads/JULIA_NUM_GC_THREADS
controls the GC threads. Julia's threads are real, with no GIL — and that is why data races are
real too: without explicit synchronisation (Atomic, ReentrantLock, channels) code with mutable
shared state is incorrect, not slow.
- Tasks migrate between threads within the same threadpool: do not assume affinity and do not use
threadid() to index per-thread buffers (the classic broken pattern); use OncePerTask/per-task
structures or partition the work explicitly.
Distributed (or MPI.jl) for multi-process/multi-node when the problem does not fit on one
machine or when you want isolation. Cost: serialisation between processes and worker start-up.
- Never launch more threads than the cores assigned to the container: set
JULIA_NUM_THREADS
explicitly in the deployment.
Operability:
- Structured logging over
Logging with a correlation id; metrics and traces exported
(observability-standards for the pipeline). /healthz and /readyz endpoints in services.
- Explicit timeouts on every outbound call;
Base.exit_on_sigint(false) and SIGTERM handling for a
clean shutdown of tasks and connections.
- Pin the seed and record the Julia version and the hash of the
Manifest.toml alongside any published
numerical result: without that it is not reproducible even if the code is in git.
- Interop:
PythonCall respects the GIL — real parallelism ends at the boundary with Python; every
long ccall blocks GC safepoints unless @ccall ... gc_safe=true.
7. Long-term sustainability
- Cadence: minors every ~4-5 months, each minor supported only until the next one ships.
Choosing "stable" implies a continuous upgrade commitment; choosing LTS implies staying out of
features for years and accepting that ecosystem packages are starting to require 1.12+. It is an
operational decision, not a matter of taste: decide it explicitly and put it in
[compat].
- Pre-1.0 ecosystem: a large share of packages live in
0.x, where SemVer gives 0.x.y → 0.(x+1).0
the status of a break. Strict [compat] and upgrades with a green suite, not a blind Pkg.update().
A critical pre-1.0 dependency with a single maintainer is project risk: measure it.
- The ecosystem is smaller than Python's or R's. Before adopting: recent maintenance, number of
maintainers, and whether the package follows the latest LTS. The answer "we will write it ourselves"
is more frequent here — and it is a cost, not an advantage.
- Your own deprecations:
Base.depwarn + changelog + window; third-party ones are debt with an issue.
- The debt of analysis that becomes a service: a research script with globals, chained
include()
and top-level state is not wrapped in an HTTP server: it is rewritten as a package with tests,
annotated types and @inferred on the hot path. In Julia this is not just hygiene: top-level code
with untyped globals is also the slowest pattern in the language, so the debt is charged in latency
and in a CPU bill from day one.
When NOT to choose Julia (honesty first):
- ❌ A CLI or serverless with frequent start-up and short execution: start-up latency eats you alive,
unless you take on
juliac --trim (experimental) or a sysimage and its limitations.
- ❌ Web/CRUD backend, systems integration, infrastructure scripting: a far poorer ecosystem and a
maintenance team that is harder to find.
- ❌ Julia "because it is faster" before having measured vectorised Python (NumPy/Polars) or R with
data.table. If the work is already a call into BLAS or a native library, Julia will give you
nothing.
- ❌ Julia because one person on the team knows it, in an artifact with an SLA that others will
maintain.
- ✅ Julia is the right answer when the bottleneck is a numerical loop that cannot be vectorised
(step-by-step simulation, ODE/PDE solving, optimisation, Monte Carlo methods, autodifferentiation
over your own code), and the alternative today is "prototype in Python + rewrite in C++" — that is,
when eliminating the two-language problem is the real benefit. Also when you want generic
composition across libraries (units, dual numbers, uncertainty) that in other languages would require
rewriting the library.
- ✅ Python (see
python-standards) when the work is engineering around the computation: service,
integration, production ML, orchestration, or when the ecosystem already has the library.
- ✅ R (see
r-standards) for statistical modelling, biostatistics, publishable graphics and
reproducible reports. The choice is almost never "R or Julia": they share the niche of "a
scientific language that is not Python" and nothing else — R is statistics and communication of
results, Julia is numerical performance.
List of prohibitions (veto):
- ❌ An application or service deployed without a versioned
Manifest.toml; Pkg.update() at deploy time.
- ❌ Publishing a package with a versioned
Manifest.toml, or without [compat] for all its deps.
- ❌ Installing a project's dependencies into the global
@v1.x environment.
- ❌
deserialize() over untrusted input; Serialization as a persistence or interchange format
across versions/machines.
- ❌
eval/@eval/Meta.parse over user input. include() of a path built with input.
- ❌ Type piracy (methods over functions and types that are not yours).
Aqua.jl must block it.
- ❌
@inbounds without having proved the indices are correct; --check-bounds=no in production;
@simd over non-independent iterations or where the numerical result must be deterministic.
- ❌ Heavy work at the top level of the script; untyped mutable globals as configuration.
- ❌ A
struct with abstract-typed or Any fields on the hot path.
- ❌
@time as a performance measurement (it measures compilation); optimising without a prior
@code_warntype.
- ❌
threadid() to index per-thread state (tasks migrate).
- ❌ Mutable shared state between threads without explicit synchronisation.
- ❌ Empty
catch e end; @assert to validate user input.
- ❌
ccall without GC.@preserve over Julia-managed memory; third-party .so files outside a JLL.
- ❌ Running on an EOL version (1.11 is one) "because it works".
- ❌ Leaving
JuliaFormatter or JET.jl without a pinned version in CI.
8. Mandatory web verification
Before pinning versions or decisions, verify online (WebSearch/WebFetch; for versions, GitHub
Releases Atom feeds and julialang.org/downloads/manual-downloads — not the summariser over the GitHub
Releases HTML):
- The current stable and LTS and which one is EOL (
julialang.org/downloads/manual-downloads,
endoflife.date/julia). As of Aug 2026: stable 1.12.6 (2026-04-09), LTS 1.10.11
(2026-03-09), 1.11 EOL. 1.13 was not final as of Aug 2026 (rc2 on 2026-07-29): check
whether it has shipped, because when it does 1.12 goes EOL and you have to decide whether the
LTS moves.
- The real state of latency: there is a lot of expired information. The native code cache is from
1.9; verify in the release notes of the version you are going to use what has changed since
then, and the state of
--trim/juliac (as of Aug 2026: experimental, requires
--experimental, no reachable dynamic dispatch). Do not quote TTFX figures from blogs without
reproducing them.
- Versions of
juliaup, PackageCompiler.jl, JuliaFormatter.jl, Documenter.jl, Aqua.jl and
JET.jl — the last one is pre-1.0 and its compatibility is tied to the Julia version: check
which JET release supports your Julia before putting it in CI.
- Vulnerability auditing: whether
Pkg.audit exists yet (as of Aug 2026 no, it remains an
open proposal in Pkg.jl) and which scanners already consume the JLSEC-* advisories of
SecurityAdvisories.jl in OSV format. Gap not verified as of Aug 2026: the effective coverage of
the JLL packages (mapping the upstream binary and its CVE to the JLL name) is something I have
not been able to quantify — treat it as not covered and do not claim otherwise.
- Gap not verified as of Aug 2026: the state of support for Python 3.14 in
PythonCall.jl
(sources indicate failures and a lack of support, with no resolution date) and whether PyCall.jl
is still the only route in that case.
- Licence changes or maintenance mode of any tool you pin as a default before adopting it
(precedents in other ecosystems: Trivy, gitleaks, Brakeman). Julia and its stdlibs are MIT, but
verify the raw
LICENSE of every third-party package that enters the critical path.
- Breaking changes from Julia's official
NEWS.md before any minor upgrade — never from third-party
blogs without cross-checking against the source.
If the web contradicts this document, the web wins — flag the discrepancy.
1---2name: julia-standards3description: Use when writing, reviewing or deploying Julia code - .jl files, Project.toml, Manifest.toml, JuliaProject.toml, .JuliaFormatter.toml, Pkg REPL mode and Pkg.instantiate, juliaup channels, multiple dispatch and method definitions, type stability with @code_warntype or @inferred, @allocated/@benchmark/BenchmarkTools, @inbounds/@simd/@views broadcasting, Threads.@spawn/@threads/Distributed, ccall/PythonCall/PyCall/RCall interop, Test/Aqua.jl/JET.jl suites, Documenter.jl docs, or PackageCompiler/juliac binaries.4---56# Julia standards (reference: August 2026)78Criteria verified as of **August 2026**. Re-verify on the web before committing to anything (§8).910## 1. Scope and triggers1112Applies to all Julia work: packages, numerical code, environments, tests, packaging and deployment.13Triggers: `.jl`, `Project.toml`, `Manifest.toml`, `.JuliaFormatter.toml`, `test/runtests.jl`, `juliaup`,14`Threads.@spawn`, `@code_warntype`, `ccall`, `PythonCall`.1516**The two axes of this skill.** (1) **Multiple dispatch is the language**: it is not sugar over OOP,17it is the mechanism of composition and extension, and almost every design error in Julia is a dispatch18design error (badly cut type hierarchies, *type piracy*, methods that are too specific or too lax).19(2) **Latency** ("time to first plot") is the language's historical objection and there is a great deal20of expired information about it: the problem is not solved, it is **bounded** — the native code cache21arrived in **1.9**, not in the recent versions, and current work is on *trimming* and standalone22binaries. Any claim about latency is verified against the version you are going to use, not against a232022 blog post.2425**Not applicable**: see `mlops-standards` (**the model lifecycle is theirs**: model registry and26versioning, *feature store*, serving, drift monitoring, retraining, *train/serve skew* —27**how the Julia that trains or scores is written belongs here**), `data-engineering-standards`28(ingestion, orchestration, idempotency, *backfill*, Parquet, freshness SLA: the platform is theirs; the29computation code that consumes it belongs here), `analytics-bi-standards` (the dashboard and who30decides with it; the code that produces the figures, here), `data-warehouse-modeling-standards` (the31shape of the analytical model), `lakehouse-standards` (table format and catalogue),32`sql-standards` (**the SQL you write via `DBInterface`/`LibPQ` is subject to their criteria**),33`python-standards` (§7 sets when the right answer is Python), `r-standards` (statistics and34communication of results; see §7), `gpu-computing-standards` (the GPU as a resource that is35provisioned, shared, monitored and paid for: driver, CUDA, MIG, quotas, cost; **the kernel and the36`CUDA.jl`/`KernelAbstractions.jl` code that uses it belongs here**), `llm-app-engineering-standards`37and `rag-standards` (the AI application layer), `ai-governance-standards` (governance and compliance),38`c-standards`/`cpp-standards` (**the native code on the other side of a `ccall`**: memory, UB,39sanitizers, ABI; the boundary from Julia —`ccall`, `Ptr`, `GC.@preserve`, `unsafe_*`, JLL— belongs40here), `fortran-standards` (**the Fortran kernel on the other side of a `ccall`**: `bind(c)`,41contiguity, index order, parallelism model and compiler flags are theirs; the boundary from Julia42belongs here), `cicd-standards` (the pipeline that runs the gates of §4), `kubernetes-standards`43(image and deployment), `appsec-standards` (agnostic threat modelling; here only the Julia *sinks*),44`vulnerability-management-standards` (triage and finding SLA; here only the state of scanning),45`secrets-management-standards`, `observability-standards` (OTel/Prometheus pipeline; here only the46instrumentation in the code), `api-design-standards` (the **contract** of an HTTP service in Julia:47resources, codes, pagination, versioning).4849## 2. Default decisions / Toolchain5051> Verify the latest version on the web before pinning it in a real project (§8).5253| Piece | Choice | Verified as of Aug 2026 | Why |54|---|---|---|---|55| Runtime (production) | **LTS** unless there is a concrete need | **1.10.11 (2026-03-09)** is the current LTS | Julia supports each minor **only until the next one ships**: 1.11 is already EOL. Without LTS, "stable" implies an upgrade every ~4-5 months |56| Runtime (features/performance) | **Current stable** | **1.12.6 (2026-04-09)** | 1.12 will expire when 1.13 ships. **1.13 is not final as of Aug 2026** (rc2 on 2026-07-29); `master` is already 1.14-dev |57| Installer/versions | **`juliaup`** with the `lts` and `release` channels | 1.20.9 (2026-07-28) | Never the Julia from the distro's package manager |58| Environments | `Pkg` + `Project.toml` per project | — | One environment per project; never install into the global `@v1.x` environment |59| Reproducibility | **`Manifest.toml` versioned in applications** | — | See §3: in **packages** the `Manifest.toml` is NOT versioned |60| Formatting | **`JuliaFormatter`** with `.JuliaFormatter.toml` | 2.12.4 (2026-07-31) | Very high release cadence: **pin exactly** or CI breaks on its own |61| Static analysis | **`JET.jl`** | 0.12.0 (2026-07-28) | Pre-1.0 and **coupled to compiler internals**: the JET version depends on the Julia one |62| Package quality | **`Aqua.jl`** | 0.8.16 (2026-06-05) | Detects *type piracy*, method ambiguities, broken exports, unused deps, incomplete `[compat]` |63| Tests | `Test` (stdlib) | — | Sufficient; `TestItems`/`ReTest` only if the ergonomics justify it |64| Benchmarks | **`BenchmarkTools.jl`** (`@benchmark`, `@btime`) | — | A bare `@time` measures compilation on the first call: it is useless for measuring |65| Documentation | **`Documenter.jl`** | 1.17.0 (2026-02-20) | *Doctests* in CI |66| Standalone binary | **`PackageCompiler.jl`** (*sysimage*) / **`juliac`+`--trim`** (executable) | PackageCompiler 2.4.0 (2026-06-10) | `--trim` is **experimental** (1.12+) and requires `--experimental`; it requires the absence of reachable dynamic dispatch |67| Python interop | **`PythonCall.jl`** in new code | — | `PyCall.jl` is in maintenance mode; PythonCall isolates the environment with CondaPkg and is *type-stable* by default |68| R interop | `RCall.jl` | — | — |6970**Version criteria**: if the service has an SLA and you are not going to dedicate an upgrade window71every 4-5 months, **LTS**. If you need *trimming*, the threading improvements or a package that only72supports 1.12+, stable — assuming the upgrade to 1.13 as soon as it ships. **Do not mix**: the Julia73version is pinned in `[compat]` and in CI, and the same number runs locally, in CI and in production.7475## 3. Structure and conventions7677```78MiPaquete/79 Project.toml # name, uuid, version, [deps], [compat] MANDATORY80 Manifest.toml # package: .gitignore | application/service: versioned81 src/MiPaquete.jl # root module; includes and exports82 test/runtests.jl # + its own Project.toml in test/83 docs/ # Documenter84 ext/ # package extensions (weak deps)85```8687- **`Manifest.toml`: the most frequently broken rule.** In an **application** (service, pipeline,88 analysis that must be reproducible) it is **always versioned**: it is the lockfile, and without it89 `Pkg.instantiate()` resolves different versions every day. In a **publishable library** it is **not**90 versioned: it would pin your consumers' dependency tree. A library's reproducibility comes from91 `[compat]`, not from the manifest. Deployment: `Pkg.instantiate()` over the versioned manifest, never92 `Pkg.update()`.93- **`[compat]` is mandatory** for every dependency and for `julia`. Without it, the General registry94 does not even accept the package, and a `[compat]` with an open upper bound turns anyone else's95 release into your failure. Use SemVer bounds (`"1"`, `"0.8.3"`), not `">=x"`.96- Registry: **General** by default; a private registry (`LocalRegistry`) for internal code. Never97 `Pkg.add(url=...)` to a branch in production — either it comes in through a registry, or it is pinned98 by commit in the manifest.99- Names: types `UpperCamelCase`, functions and variables `lowercase`/`snake_case` without underscores100 if it still reads well, constants `UPPER`; a `!` suffix on every function that **mutates** its101 arguments (and the mutated argument goes **first**). Modules = the package name.102- Minimal exports: export what is API, the rest is accessed qualified. Everything exported is103 documented and enters SemVer.104- Files per concept, not a `utils.jl`; `include()` only from the root module, in explicit order.105106**Types and dispatch — the hard rules:**107- Design **generic functions with methods**, not hierarchies. Abstract types define *interfaces* (which108 methods must exist), and that interface is **documented**: Julia does not verify it for you.109- **Annotate the field types of a `struct`, always.** An `::Any` field (or a non-concrete parametric110 type) destroys the performance of everything that touches the object. Use type parameters111 (`struct Punto{T<:Real}`) instead of abstract fields.112- `struct` **immutable by default**; `mutable struct` only when the state has to change.113- Annotating the types of the **arguments** does not speed anything up: it is for dispatch and for114 documenting the contract. Be as generic as you can (`AbstractVector{<:Real}`, not `Vector{Float64}`),115 unless you want to restrict deliberately.116- **`Union{}` and `Any` in an inference are a symptom**: `Union{}` as a return type means "this always117 throws"; `Any` means the compiler gave up. Both show up in `@code_warntype`.118119**Type piracy: a serious antipattern.** The manual's definition: *"«Type piracy» refers to the practice120of extending or redefining methods in Base or other packages on types that you have not defined."* If121neither the function nor any of the method's types are yours, you are pirating: you change the122behaviour of someone else's code globally and invisibly, and the result can range from a remote and123untraceable bug to, in extreme cases, taking Julia down. Alternatives: define your own wrapper type,124your own function, or use a `struct` with the desired behaviour. `Aqua.jl` detects it — **make that125test block the merge**.126127**Error style**: your own typed exceptions (`struct MiError <: Exception`) with `showerror`;128Base's `ArgumentError`/`DomainError`/`BoundsError` when they fit. `@assert` is for internal invariants129and **can disappear with `--check-bounds=no`/optimisations**: do not use it to validate input. No empty130`catch e end`; `try/finally` (or the `do`-block patterns) to release resources.131132## 4. Quality: formatting, analysis, tests133134- **Formatting**: `JuliaFormatter` with a versioned `.JuliaFormatter.toml`, checked in CI. **Pin the135 version exactly** in the CI environment: it publishes several versions a week and a style change136 breaks the gate without anyone having touched the code.137- **Static analysis**: `JET.jl` (`report_package`) over the package. Realistically: JET is **pre-1.0**138 and depends on compiler internals, so a Julia upgrade can change its findings. Introduce it as an139 **informative** job first and turn it into a gate when the baseline is clean; never leave its version140 floating.141- **`Aqua.jl` as a gate**: `Aqua.test_all(MiPaquete)` in `runtests.jl`. It covers what no human review142 catches: type piracy, method ambiguities, incomplete `[compat]`, declared and unused deps, exports143 that do not exist.144- **Tests (`Test` stdlib)**:145 - `@testset`s nested per unit of behaviour; one failure reason per test.146 - Mandatory edges: empty collection, one element, `NaN`/`Inf`/`-0.0`, integer overflow (**`Int` in147 Julia wraps silently**, it does not promote), singular matrix, unexpected type, `missing`148 propagating, out-of-range indices.149 - Floating point numbers: `≈` (`isapprox`) with **explicit** `atol`/`rtol`, never `==`.150 - **`@inferred` over the hot path functions**: it turns "this was type-stable" into a test that fails151 when somebody breaks it. It is the most valuable test in a Julia package.152 - `Random`: an explicit seed per test (`StableRNGs` if the result must be identical across Julia153 versions — **the `Random` RNG stream can change between minors**).154 - Every fixed bug leaves a regression test. Flaky = fixed or deleted.155- **CI gates** (they block the merge, cheapest first):156 1. `JuliaFormatter` in check mode (pinned version).157 2. Reproducible `Pkg.instantiate()` + `Aqua.test_all`.158 3. `Pkg.test()` with coverage (`Coverage.jl`/Codecov); agreed threshold, coverage is a signal.159 4. `@inferred` / performance regression benchmarks on the critical paths.160 5. `JET.jl` (informative → gate) and `Documenter` doctests.161 6. Dependency audit (§5) and artifact build.162- **CI matrix**: LTS + stable + `nightly` (the last one allowed to fail). If you support both lines,163 both are tested — saying so in the README without testing it is lying.164165## 5. Stack security166167- **`Serialization` (`serialize`/`deserialize`): it is neither an interchange format nor safe.**168 Official documentation: *"`deserialize` assumes the binary data read from `stream` is correct and has169 been serialized by a compatible implementation of `serialize`. `deserialize` is designed for170 simplicity and performance, and so does not validate the data read. Malformed data can result in171 process termination."* In addition, *"The data format can change in minor (1.x) Julia releases"* and172 the word size (32/64 bits) of the reading and the writing machine **must match**. Rules:173 **FORBIDDEN** to deserialise untrusted input; **FORBIDDEN** to use `Serialization` as a persistence174 format across versions or across machines. For data: JLD2, Arrow, Parquet, JSON or a versioned format175 of your own, always validated on read.176- **`eval` and metaprogramming**: `@eval`/`eval` over strings built with user input, and `Meta.parse`177 of input, are **arbitrary code execution: FORBIDDEN**. In addition, `eval` at runtime invalidates178 compiled code and causes recompilation (latency cost). Macros are for syntactic transformation at179 compile time; if a macro can be a function, it is a function. `include()` of paths built with input:180 forbidden.181- **`ccall` and `unsafe_*`**: `ccall` is a total trust boundary — a signature error is memory182 corruption, not an exception. Rules: signatures verified against the real header, `GC.@preserve`183 around any pointer to Julia-managed memory that crosses the boundary, and184 `unsafe_load`/`unsafe_wrap`/`unsafe_store!` only with verified length and ownership. Third-party185 binaries: **JLL** packages from the ecosystem (BinaryBuilder), never `.so` files downloaded by hand.186- **`@inbounds` and `@simd` are unsafe by construction.** `@inbounds` **removes the bounds check**:187 with a wrong index you read or write outside the array — silent memory corruption, not a188 `BoundsError`. `@simd` promises the compiler that the iterations are independent and that it may189 reorder the operations (including floating point arithmetic, so **the numerical result can change**).190 Criteria: only after measuring that they help, only in loops whose indices are provably correct by191 construction, with a test covering the extremes, and never over indices derived from external input.192 `--check-bounds=no` globally: **FORBIDDEN** in production.193- **Dependency auditing: the ecosystem is immature and that has to be said.** As of Aug 2026 **there is194 no `Pkg.audit`** in Pkg (it is still an open proposal). What does exist: the **Julia Security Advisory195 Database** (`SecurityAdvisories.jl`), with advisories identified as `JLSEC-YYYY-nnn` in an196 **OSV**-compatible format, and the **Security Working Group** created in 2025-11. Practice today:197 consume those advisories from an OSV-compatible scanner over the `Manifest.toml`, and **assume198 partial coverage** — in particular that of the >1,500 **JLL** packages, which repackage third-party199 binaries whose CVEs are not automatically mapped to the JLL name. This is the ecosystem's largest200 risk surface and today it is **not reliably covered**. Do not invent a tool that does not exist;201 declare the gap (§8).202- **SQL / commands**: parameterised queries via `DBInterface.execute(stmt, params)`; interpolating input203 into SQL is an absolute veto. `Cmd` backticks (`run(`cmd $arg`)`) do **not** go through a shell and204 that protects from shell injection — but `run(`sh -c $x`)` is injection. Never build a `Cmd` from a205 string with input.206- **Secrets**: environment variables or a manager; never in `Project.toml`, in the code, in207 `LocalPreferences.toml` or in exported Pluto notebooks. Careful with the output of `@show`/`dump`208 over config structures.209- **HTTP services**: validate and limit the body size, timeouts on every outbound call, and do not210 return *stack traces* to the client — a Julia trace exposes internal paths and package names.211- **Containers**: an image based on the official `julia:<version>` with an exact version, non-root,212 multi-stage. **The image is large** — the precompiled package depot (`~/.julia`) weighs a fair213 amount and the `PackageCompiler` *sysimage* adds hundreds of MB. Precompile **in the build**214 (`Pkg.precompile()`), never at container start-up, and discard the compiler and the build sources in215 the final stage.216217## 6. Performance and operability218219**Type stability is performance criterion number one.** If the compiler can infer a concrete type for220each value, it generates specialised code comparable to C; if not, it falls back to dynamic dispatch221and allocations, and you lose one or two orders of magnitude. Protocol, in this order:2221. `@code_warntype` over the function: anything in red (`Any`, a wide `Union{...}`) is the bug.2232. `@inferred` in the test so it does not come back.2243. `@allocated`/`@benchmark`: in a well-written numerical loop, allocations tend to **zero**.225 Unexpected allocations = type instability or accidental copies.2264. `Profile`/`ProfileView` to locate; never optimise without having measured.227228Concrete silent killers:229- **Untyped global variables**: a global without `const` can change type, so the compiler infers230 nothing from it and all its use becomes dynamic. Rule: **the work goes inside functions**, with the231 data as arguments; the globals you do need are declared `const` (or with a type annotation). A232 top-level script with a heavy loop is the slowest possible pattern.233- Containers with an abstract type: `Vector{Any}`, `Dict{String,Any}`, or a `struct` with `Any` fields.234- Functions that return different types depending on a branch.235- *Closures* that capture variables whose type changes.236237Memory and allocations:238- **`@views` / `view` instead of copies** when slicing arrays (`A[:, 1]` **copies**). In hot loops, the239 difference is everything.240- *Broadcasting* with `.` **fuses** into a single loop with no temporaries (`@.` so as not to forget a241 dot); chaining operations without `.` creates one temporary array per operation.242- Preallocate and use the `!` variants (`mul!`, `map!`, `sort!`) on the hot path.243- Arrays with a concrete element type and `StaticArrays` for small fixed-size vectors.244245**Latency (TTFX) — real state, no folklore**: the **native code** cache has existed since **Julia 1.9**246(*package images*); in exchange, precompilation is slower and the caches larger. There is still latency247on the first execution of uncached code. Tools in order of cost: (a) precompile in the image build;248(b) precompilation workloads in the package itself (`PrecompileTools`); (c) a *sysimage* with249`PackageCompiler`; (d) a standalone executable with `juliac --trim` (**experimental**, 1.12+, requires250`--experimental` and **fails if there is dynamic dispatch reachable from the entry point** — that is,251it demands strictly inferable code). For CLIs and short, frequent functions, latency is still an252argument against Julia (§7).253254Parallelism:255- **Threads** for shared memory: `Threads.@spawn` + `fetch`, `Threads.@threads` for homogeneous loops.256 Since **1.12** there is by default **1 interactive thread in addition to the worker one** (`-t1,1`),257 and `Threads.@spawn :samepool` to avoid jumping *threadpool*. `--gcthreads`/`JULIA_NUM_GC_THREADS`258 controls the GC threads. Julia's threads are **real, with no GIL** — and that is why data races are259 real too: without explicit synchronisation (`Atomic`, `ReentrantLock`, channels) code with mutable260 shared state is incorrect, not slow.261- Tasks **migrate between threads** within the same *threadpool*: do not assume affinity and do not use262 `threadid()` to index per-thread buffers (the classic broken pattern); use `OncePerTask`/per-task263 structures or partition the work explicitly.264- **`Distributed`** (or `MPI.jl`) for multi-process/multi-node when the problem does not fit on one265 machine or when you want isolation. Cost: serialisation between processes and *worker* start-up.266- Never launch more threads than the cores assigned to the container: set `JULIA_NUM_THREADS`267 explicitly in the deployment.268269Operability:270- Structured logging over `Logging` with a *correlation id*; metrics and traces exported271 (`observability-standards` for the pipeline). `/healthz` and `/readyz` endpoints in services.272- Explicit timeouts on every outbound call; `Base.exit_on_sigint(false)` and SIGTERM handling for a273 clean shutdown of tasks and connections.274- Pin the seed and record the Julia version and the hash of the `Manifest.toml` alongside any published275 numerical result: without that it is not reproducible even if the code is in git.276- Interop: `PythonCall` respects the GIL — real parallelism ends at the boundary with Python; every277 long `ccall` blocks GC safepoints unless `@ccall ... gc_safe=true`.278279## 7. Long-term sustainability280281- **Cadence**: minors every ~4-5 months, **each minor supported only until the next one ships**.282 Choosing "stable" implies a continuous upgrade commitment; choosing LTS implies staying out of283 features for years and accepting that **ecosystem packages are starting to require 1.12+**. It is an284 operational decision, not a matter of taste: decide it explicitly and put it in `[compat]`.285- Pre-1.0 ecosystem: a large share of packages live in `0.x`, where SemVer gives `0.x.y → 0.(x+1).0`286 the status of a break. Strict `[compat]` and upgrades with a green suite, not a blind `Pkg.update()`.287 A critical pre-1.0 dependency with a single maintainer is project risk: measure it.288- The ecosystem is **smaller than Python's or R's**. Before adopting: recent maintenance, number of289 maintainers, and whether the package follows the latest LTS. The answer "we will write it ourselves"290 is more frequent here — and it is a cost, not an advantage.291- Your own deprecations: `Base.depwarn` + changelog + window; third-party ones are debt with an issue.292- **The debt of analysis that becomes a service**: a research script with globals, chained `include()`293 and top-level state **is not wrapped in an HTTP server: it is rewritten as a package with tests,294 annotated types and `@inferred` on the hot path**. In Julia this is not just hygiene: top-level code295 with untyped globals is also the slowest pattern in the language, so the debt is charged in latency296 and in a CPU bill from day one.297298**When NOT to choose Julia** (honesty first):299- ❌ A CLI or *serverless* with frequent start-up and short execution: start-up latency eats you alive,300 unless you take on `juliac --trim` (experimental) or a *sysimage* and its limitations.301- ❌ Web/CRUD backend, systems integration, infrastructure *scripting*: a far poorer ecosystem and a302 maintenance team that is harder to find.303- ❌ Julia "because it is faster" **before having measured vectorised Python (NumPy/Polars) or R with304 `data.table`**. If the work is already a call into BLAS or a native library, Julia will give you305 nothing.306- ❌ Julia because one person on the team knows it, in an artifact with an SLA that others will307 maintain.308- ✅ **Julia is the right answer** when the bottleneck is **a numerical loop that cannot be vectorised**309 (step-by-step simulation, ODE/PDE solving, optimisation, Monte Carlo methods, autodifferentiation310 over your own code), and the alternative today is "prototype in Python + rewrite in C++" — that is,311 when eliminating the **two-language problem** is the real benefit. Also when you want generic312 composition across libraries (units, dual numbers, uncertainty) that in other languages would require313 rewriting the library.314- ✅ **Python** (see `python-standards`) when the work is engineering around the computation: service,315 integration, production ML, orchestration, or when the ecosystem already has the library.316- ✅ **R** (see `r-standards`) for statistical modelling, biostatistics, publishable graphics and317 reproducible reports. **The choice is almost never "R or Julia"**: they share the niche of "a318 scientific language that is not Python" and nothing else — R is statistics and communication of319 results, Julia is numerical performance.320321**List of prohibitions (veto):**322- ❌ An application or service deployed without a versioned `Manifest.toml`; `Pkg.update()` at deploy time.323- ❌ Publishing a **package** with a versioned `Manifest.toml`, or without `[compat]` for all its deps.324- ❌ Installing a project's dependencies into the global `@v1.x` environment.325- ❌ `deserialize()` over untrusted input; `Serialization` as a persistence or interchange format326 across versions/machines.327- ❌ `eval`/`@eval`/`Meta.parse` over user input. `include()` of a path built with input.328- ❌ **Type piracy** (methods over functions and types that are not yours). `Aqua.jl` must block it.329- ❌ `@inbounds` without having proved the indices are correct; `--check-bounds=no` in production;330 `@simd` over non-independent iterations or where the numerical result must be deterministic.331- ❌ Heavy work at the top level of the script; untyped mutable globals as configuration.332- ❌ A `struct` with abstract-typed or `Any` fields on the hot path.333- ❌ `@time` as a performance measurement (it measures compilation); optimising without a prior334 `@code_warntype`.335- ❌ `threadid()` to index per-thread state (tasks migrate).336- ❌ Mutable shared state between threads without explicit synchronisation.337- ❌ Empty `catch e end`; `@assert` to validate user input.338- ❌ `ccall` without `GC.@preserve` over Julia-managed memory; third-party `.so` files outside a JLL.339- ❌ Running on an EOL version (1.11 is one) "because it works".340- ❌ Leaving `JuliaFormatter` or `JET.jl` without a pinned version in CI.341342## 8. Mandatory web verification343344Before pinning versions or decisions, **verify online** (WebSearch/WebFetch; for versions, GitHub345Releases Atom feeds and `julialang.org/downloads/manual-downloads` — not the summariser over the GitHub346Releases HTML):3471. **The current stable and LTS and which one is EOL** (`julialang.org/downloads/manual-downloads`,348 `endoflife.date/julia`). As of Aug 2026: stable **1.12.6 (2026-04-09)**, LTS **1.10.11349 (2026-03-09)**, **1.11 EOL**. **1.13 was not final as of Aug 2026** (rc2 on 2026-07-29): check350 whether it has shipped, because when it does **1.12 goes EOL** and you have to decide whether the351 LTS moves.3522. **The real state of latency**: there is a lot of expired information. The native code cache is from353 **1.9**; verify in the release notes of the version you are going to use what has changed since354 then, and the state of `--trim`/`juliac` (as of Aug 2026: **experimental**, requires355 `--experimental`, no reachable dynamic dispatch). Do not quote TTFX figures from blogs without356 reproducing them.3573. Versions of `juliaup`, `PackageCompiler.jl`, `JuliaFormatter.jl`, `Documenter.jl`, `Aqua.jl` and358 **`JET.jl`** — the last one is pre-1.0 and its compatibility is tied to the Julia version: check359 which JET release supports your Julia before putting it in CI.3604. **Vulnerability auditing**: whether `Pkg.audit` exists yet (as of Aug 2026 **no**, it remains an361 open proposal in Pkg.jl) and which scanners already consume the `JLSEC-*` advisories of362 `SecurityAdvisories.jl` in OSV format. **Gap not verified as of Aug 2026**: the effective coverage of363 the **JLL** packages (mapping the upstream binary and its CVE to the JLL name) is something I have364 not been able to quantify — treat it as **not covered** and do not claim otherwise.3655. **Gap not verified as of Aug 2026**: the state of support for **Python 3.14 in `PythonCall.jl`**366 (sources indicate failures and a lack of support, with no resolution date) and whether `PyCall.jl`367 is still the only route in that case.3686. **Licence changes or maintenance mode** of any tool you pin as a default before adopting it369 (precedents in other ecosystems: Trivy, gitleaks, Brakeman). Julia and its stdlibs are MIT, but370 verify the raw `LICENSE` of every third-party package that enters the critical path.3717. Breaking changes from Julia's official `NEWS.md` before any minor upgrade — never from third-party372 blogs without cross-checking against the source.373374If the web contradicts this document, **the web wins** — flag the discrepancy.