Open-source project
JuliaArrays/StaticArrays.jl avatar
JuliaArrays/StaticArrays.jl

StaticArrays.jl puts the array size in the type

Statically sized arrays for Julia

849 stars163 forksJuliaNOASSERTION

At a glance

What is it?
StaticArrays.jl is a Julia package for arrays whose length and shape are part of their type, which lets the compiler specialise common array and linear algebra operations. It pays off for small vectors and matrices, and it stops paying off once the elements pass roughly one hundred.
Who is it for?
StaticArrays.jl suits engineers writing simulation kernels, robotics code and linear algebra on small fixed size vectors and matrices, where it removes heap allocation and gives the compiler a size it can specialise on. It is the wrong tool for large or runtime sized data, where a plain Base.Array is faster and easier to reason about.
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 7 days ago.
What is it written in?
Mainly Julia, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The size is a type parameter, not a runtime property

The central idea of StaticArrays.jl is stated in the README: the package provides a framework for implementing statically sized arrays in Julia, using the abstract type StaticArray{Size,T,N} <: AbstractArray{T,N}. A normal Julia Array carries its length in a field of the value, so a function that receives one cannot know how many elements it holds until it looks at the value. A subtype of StaticArray encodes size in the type, so the length is available to the compiler before the code runs. That is what lets the package provide fast implementations of common array and linear algebra operations rather than generic loops.

The README also draws a line that matters for anyone designing their own types. Here statically sized means that the size can be determined from the type, and static does not necessarily imply immutable. Size and mutability are separate axes, and the package exports both kinds.

The concrete types follow from that. SVector, SMatrix and SArray are the immutable family. MVector, MMatrix and MArray are the mutable counterparts, useful when a value has to change in place while keeping its size visible in the type. SizedArray wraps a standard Array and annotates it with static size information, which lets a plain Array borrow the specialised methods without changing how the data is stored. The abstract FieldVector goes one step further and lets you build a fast StaticVector out of any uniform Julia struct, which is how a package can attach its own fields to a vector without giving up the static length.

Tuple storage, compile time Size, and a mutable escape hatch

Storage for the immutable types is a tuple rather than a heap allocated buffer. The README shows this directly:

julia
v1 = SVector(1, 2, 3)
v1.data === (1, 2, 3) # SVector uses a tuple for internal storage

A tuple is a compile time known set of values, so the compiler can unroll operations over it. The same idea appears in the Size trait, which the README calls a compile time constant representing the size. You can ask for it from an instance or from the type:

julia
size(v1) == (3,)
size(typeof(v1)) == (3,)

The type is not the only way to build these values. The convenience constructor SA builds them directly:

julia
SA[1, 2, 3]      isa SVector{3,Int}
SA_F64[1, 2, 3]  isa SVector{3,Float64}
SA[1 2; 3 4]     isa SMatrix{2,2,Int}

The @SVector and @SMatrix macros cover the cases where the values come from a literal or a comprehension, and the README notes that a comprehension is evaluated at global scope. Conversions from a regular Array have to state the size, because the compiler cannot read it off a value:

julia
v7 = SVector{3}([1, 2, 3]) # Array conversions must specify size
m5 = SMatrix{2,2}([1 3 ; 2 4]) # Array conversions must specify size

One subtle point is worth knowing before you write code against these types. similar() returns a mutable container, while similar_type() returns a constructor. The README gives the exact types:

julia
typeof(similar(m3)) == MArray{Tuple{3,3},Int64,2,9} # (final parameter is length = 9)
similar_type(m3) == SArray{Tuple{3,3},Int64,2,9}

So a routine that assumes an immutable result from similar() will silently get a mutable MArray back, and a routine that assumes similar() preserves immutability will get a surprise.

Installing the package and running a first small linear algebra session

The README points to the Pkg REPL for installation and gives the command `pkg> add StaticArrays` as the install step. After that, the package is loaded like any other Julia package:

julia
using LinearAlgebra
using StaticArrays

A first useful exercise is to build a 3 by 3 identity matrix as a static value and factor it. The README shows both the constructor and the macro form:

julia
m3 = SMatrix{3,3}(1I)
eigen(m3) # eigen(), etc uses specialized algorithms up to 3×3, or else LAPACK

The comment is worth reading twice. For small matrices the package uses specialised algorithms, and above three by three it falls back to LAPACK. The static property survives the call, which the README demonstrates by checking the resulting types:

julia
typeof(eigen(m3).vectors) == SMatrix{3,3,Float64,9}
typeof(eigen(m3).values) == SVector{3,Float64}

That is the practical payoff of the type level design. Nothing about the result had to be converted or copied; the size was known statically and stayed known.

You can also take an existing Array and wrap it, which is the gentlest way to introduce the package into an existing code base:

julia
m4 = SizedMatrix{3,3}(rand(3,3))
inv(m4) # Take advantage of specialized fast methods

And you can reshape a plain vector into a static matrix using the Size trait, since reshape needs to know the target shape:

julia
reshape([1,2,3,4], Size(2,2)) == @SMatrix [ 1  3 ;
                                            2  4 ]

Note that the result of that reshape is a SizedArray rather than an SMatrix, so reshape gives you static size information without demanding a tuple backed value.

The compiler cost grows with the number of elements

The README is unusually direct about the ceiling of this approach. In the current implementation, working with large StaticArrays puts a lot of stress on the compiler, and becomes slower than Base.Array as the size increases. It gives a rough rule of thumb: consider using a normal Array for arrays larger than 100 elements.

That is a hard boundary for planning. If a design document says a buffer will hold a few hundred or thousand elements, a static type is the wrong container, and the reason is not overhead in the usual sense. The cost is in the compiler generating specialised code for a large number of elements, and in the resulting code being slower than the generic path.

The speedups on offer are also documented with the same caution. The README presents a microbenchmark of 3 by 3 Float64 matrices:

code
============================================
    Benchmarks for 3×3 Float64 matrices
============================================
Matrix multiplication               -> 5.9x speedup
Matrix multiplication (mutating)    -> 1.8x speedup
Matrix addition                     -> 33.1x speedup
Matrix addition (mutating)          -> 2.5x speedup
Matrix determinant                  -> 112.9x speedup
Matrix inverse                      -> 67.8x speedup
Matrix symmetric eigendecomposition -> 25.0x speedup
Matrix Cholesky decomposition       -> 8.8x speedup
Matrix LU decomposition             -> 6.1x speedup
Matrix QR decomposition             -> 65.0x speedup

The README states these numbers were generated on an Intel i7-7700HQ using Julia-1.2, and that with synthetic benchmarks like these the speedups should only be taken as very roughly indicative. It then says to benchmark your real application. Treat the table as an order of magnitude guide for three by three Float64 matrices, not as a prediction for your code.

A second practical constraint appears in the same section. The number of elements is a type parameter, so a static array type is a distinct type for every size. Code that generates static arrays across many different sizes will multiply the amount of code the compiler has to generate, and that is where the compiler stress comes from in practice.

StaticArraysCore keeps downstream packages off the heavy load path

The architecture has one decision that pays off for anyone building on top of the package. Most of the primary array types exported by StaticArrays.jl are defined in the small interface package StaticArraysCore.jl. That includes the abstract type StaticArray and the concrete types SArray, MArray and SizedArray, along with their dimension specific aliases.

The stated reason is dependency hygiene rather than raw speed. This lets downstream packages implement new methods for these types without depending on, and hence loading, the entirety of StaticArrays.jl, and thereby avoid incurring the full load time of StaticArrays.jl. The README puts a number on that load time: on the order of 0.6 s for StaticArrays.jl v1.4 on Julia v1.7. That figure is tied to a specific old version, but the structural point still holds. A library that only needs to define a method on StaticArray can depend on the interface package and skip the full package load.

The repository layout matches this design. Top level entries include Project.toml, README.md, LICENSE.md, and the directories src, test, docs, ext, benchmark and perf. The ext directory signals that the package uses Julia's extension mechanism, and the perf directory holds the benchmark scripts referenced from the README, including perf/README_benchmarks.jl. The docs directory backs the stable and dev documentation links shown at the top of the README.

The split also has a cost for contributors. Two packages have to keep their interfaces aligned, and a type that lives in StaticArraysCore but a method that lives in StaticArrays means the boundary has to be maintained by hand rather than derived from a single file.

Choosing between an SVector, an MVector and a plain Array

The choice is not between static and dynamic only, but between two kinds of static. The immutable types store their contents in a tuple, and the mutable types store them in a form you can write into while keeping the size in the type. The README shows both on the same footing:

julia
rand(MMatrix{20,20}) * rand(MMatrix{20,20}) # large matrices can use BLAS

That line also shows the escape hatch for size. The comment states that large matrices can use BLAS, so a mutable static matrix is not limited to the small specialised paths.

Against those, Base.Array is the general purpose container. It supports runtime sized data, it accepts any size without generating a new type, and it does not stress the compiler. The README is clear that the specialised methods apply to small arrays, and its own advice is to use a normal Array above roughly one hundred elements. Base.Array also wins on cases the package is not designed for, such as a data structure whose length is only known once the input has been read.

SizedArray is the middle path. It annotates a standard Array with static size information, so the size is known to the type system without changing how the data is stored, and the README notes it lets you take advantage of specialised fast methods. It is the option to reach for when the storage has to stay a normal Array but the size is fixed in practice.

The package is a specialised tool, and the choice of tool should follow the size of the data. Fixed, small, hot: static. Fixed, large: BLAS backed MMatrix or a plain Array. Unknown until runtime: plain Array.

Release cadence, maintenance state and the licence question

The repository is not archived, and the last push was on 2026-10-12. Recent tagged releases include v1.9.23 on 2026-10-08, v1.9.22 on 2026-09-17 and v1.9.21 on 2026-09-16. The version numbers and the release dates sit close together, so upgrading is not a rare event and you should expect to move through patch releases regularly.

Licensing needs a direct check rather than an assumption. GitHub cannot classify the licence for this repository and reports it as Other, pointing to the licence file in the repository, which is listed at the top level as LICENSE.md. Since the classification is not one of the well known standard identifiers, you need to read LICENSE.md yourself and confirm the terms that apply to your use, including any conditions on redistribution or attribution. Nothing in the README summarises the licence terms, and this article does not interpret them.

The documentation split also affects upgrades. The README carries separate stable and dev documentation links, so the dev documentation can describe behaviour that has not been released yet. When you are checking whether a change is safe, compare the stable documentation for the version you have pinned against the release notes for the tag you plan to move to.

Editorial conclusion

StaticArrays.jl suits engineers writing simulation kernels, robotics code and linear algebra on small fixed size vectors and matrices, where it removes heap allocation and gives the compiler a size it can specialise on. It is the wrong tool for large or runtime sized data, where a plain Base.Array is faster and easier to reason about. Before adopting it, check the licence text in the repository's LICENSE.md file yourself, since GitHub classifies the licence as Other, and confirm that your real workload stays small, because the README's own threshold is about one hundred elements and large static arrays are slower than Base.Array.

Frequently asked questions

How do I install StaticArrays.jl in Julia?

The README points to the Pkg REPL and gives the command `add StaticArrays` as the install step, after which the package is loaded with `using StaticArrays`. The README also links the stable documentation hosted on the JuliaArrays GitHub Pages site for further detail.

When should I use a plain Array instead of an SVector in Julia?

The README gives a rough rule of thumb that you should consider using a normal Array for arrays larger than 100 elements, because working with large static arrays puts a lot of stress on the compiler and becomes slower than Base.Array as size increases.

What is the difference between SVector and MVector in StaticArrays.jl?

SVector is the immutable form, backed by a tuple for internal storage, while MVector is the mutable form that keeps the size in the type while allowing in place writes. The package also documents that similar() returns a mutable container while similar_type() returns a constructor, so the two families differ in more than a keyword.

What licence is StaticArrays.jl released under?

GitHub does not classify the licence for this repository and reports it as Other, pointing to the licence file in the repository, which is listed at the top level as LICENSE.md. The README does not summarise the terms, so the file itself has to be read to check the conditions.

Official sources

  1. Issues
  2. JuliaArrays/StaticArrays.jl on GitHub
  3. README
  4. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/juliaarrays-staticarrays-jl.svg)](https://hysenlabs.com/projects/juliaarrays-staticarrays-jl)

Was this useful?