Skip to content

Commit b78e905

Browse files
committed
docs: Blog anouncing Fable 5 RC (#224)
1 parent f13e7ef commit b78e905

3 files changed

Lines changed: 227 additions & 0 deletions

File tree

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
---
2+
layout: fable-blog-page
3+
title: Announcing Fable 5 Release Candidate
4+
author: Mangel Maxime
5+
date: 2026-02-27
6+
author_link: https://twitter.com/MangelMaxime
7+
author_image: https://github.com/MangelMaxime.png
8+
# external_link:
9+
abstract: |
10+
Fable 5 RC is Here: New Targets, Better Tooling, and Nullness Support
11+
---
12+
13+
More than a year after the first alpha release, we are happy to announce that Fable 5 is now in the release candidate stage!
14+
15+
You can install Fable 5 by running the following command:
16+
17+
```bash
18+
# If you haven't installed a dotnet tool in this directory yet
19+
dotnet new tool-manifest
20+
21+
dotnet tool install fable --prerelease
22+
```
23+
24+
If you already have Fable installed, you can update it by running:
25+
26+
```bash
27+
dotnet tool update fable --prerelease
28+
```
29+
30+
:::info
31+
When upgrading, make sure to upgrade your dependencies as well.
32+
:::
33+
34+
## Compatibility with Fable 4
35+
36+
Fable 5 is compatible with Fable 4 projects, except that it now targets `net10.0`.
37+
38+
## Project cracking
39+
40+
We removed support for the old project cracker using Buildalyzer. This has been replaced by invoking MSBuild directly, which should be more robust for the future.
41+
42+
## `WarnAsError` support
43+
44+
It has been a long-standing request to support `<TreatWarningsAsErrors>true</TreatWarningsAsErrors>` in Fable, and we are happy to announce that it is now supported in Fable 5.
45+
46+
You can enable it in your project file like this:
47+
48+
```xml
49+
<PropertyGroup>
50+
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
51+
</PropertyGroup>
52+
```
53+
54+
Fable will now treat all warnings from **your** code as errors, but it will still allow warnings from dependencies.
55+
56+
This behavior should mimic how the standard F# compiler works.
57+
58+
## .NET 10 and F# 10 support
59+
60+
Fable 5 adds support for the following F# features:
61+
62+
* [Nullable reference types](https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-9#nullable-reference-types)
63+
* [Discriminated union <code>.Is*</code> properties](https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-9#discriminated-union-is-properties)
64+
* [Partial active patterns can return <code>bool</code> instead of <code>unit option</code>](https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-9#partial-active-patterns-can-return-bool-instead-of-unit-option)
65+
* [Empty-bodied computation expressions](https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-9#empty-bodied-computation-expressions)
66+
* [Updates to the standard library (FSharp.Core)](https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-9#updates-to-the-standard-library-fsharpcore)
67+
68+
## JavaScript / TypeScript
69+
70+
The JavaScript target is still the most used and stable target, and we have continued to improve it over the past year.
71+
72+
### Support for direct nested types when using `jsOptions`
73+
74+
```fs
75+
let opts =
76+
jsOptions<Level1> (fun o ->
77+
o.level2.level3.valueA <- 10
78+
o.level2.level3.valueB <- 20
79+
o.topValueA <- 20
80+
)
81+
```
82+
83+
generates
84+
85+
```js
86+
export const opts = {
87+
level2: {
88+
level3: {
89+
valueA: 10,
90+
valueB: 20,
91+
},
92+
},
93+
topValueA: 20,
94+
};
95+
```
96+
97+
### Simplify `Pojo` bindings
98+
99+
Fable has a number of ways to create [Plain Old JavaScript Objects](https://fable.io/docs/javascript/features.html#plain-old-javascript-objects) (POJOs).
100+
101+
In Fable 4, people discovered a way of abusing a combination of attributes to write POJO bindings in a natural F# way.
102+
103+
```fs
104+
open Fable.Core
105+
106+
[<AllowNullLiteral>]
107+
[<Global>]
108+
type Options
109+
[<ParamObject; Emit("$0")>]
110+
(
111+
searchTerm: string,
112+
?isCaseSensitive: bool
113+
) =
114+
member val searchTerm: string = jsNative with get, set
115+
member val isCaseSensitive: bool option = jsNative with get, set
116+
117+
let options1 = new Options("foo")
118+
119+
let options2 = new Options("foo", isCaseSensitive = true)
120+
```
121+
122+
Improving on this, Fable 5 introduces a new attribute, `Pojo`, that can be used to write the same code with only one attribute:
123+
124+
```fs
125+
open Fable.Core
126+
127+
[<AllowNullLiteral>]
128+
[<JS.Pojo>]
129+
type Options
130+
(
131+
searchTerm: string,
132+
?isCaseSensitive: bool
133+
) =
134+
member val searchTerm: string = jsNative with get, set
135+
member val isCaseSensitive: bool option = jsNative with get, set
136+
137+
let options1 = new Options("foo")
138+
139+
let options2 = new Options("foo", isCaseSensitive = true)
140+
```
141+
142+
Both examples generate the same JavaScript code:
143+
144+
```js
145+
export const options1 = {
146+
searchTerm: "foo",
147+
};
148+
149+
export const options2 = {
150+
searchTerm: "foo",
151+
isCaseSensitive: true,
152+
};
153+
```
154+
155+
## Python
156+
157+
If you have been following the Fable 5 alpha releases, you know the Python target has received a staggering amount of love.
158+
159+
This is all thanks to Dag and the early adopters who have been testing it.
160+
161+
* **Python 3.12-3.14 support** (3.10/3.11 are deprecated)
162+
* **fable-library via PyPI** - No more bundled runtime files
163+
* **Modern type parameter syntax** - Better type hinting in generated code
164+
* **`Py.Decorate` attribute** - Add Python decorators from F#
165+
* **`Py.ClassAttributes` attribute** - Fine-grained class generation control
166+
* **Improved Pydantic interop** - First-class support for data validation
167+
168+
### Rust Core with PyO3
169+
170+
One of the biggest changes is that the core of fable-library is now written in Rust using PyO3.
171+
The motivation here is **correctness**, not performance:
172+
173+
**Why Rust?**
174+
175+
* **Correct .NET semantics** - Sized/signed integers (int8, int16, int32, int64, uint8, etc.)
176+
* **Proper overflow behavior** - Matches .NET exactly
177+
* **Fixed-size arrays** - No more Python list quirks for byte streams
178+
* **Reliable numerics** - Fable 4's pure Python numerics were a constant source of bugs
179+
180+
### fable-library via PyPI
181+
182+
Before Fable v5, the runtime was bundled in the NuGet package and copied to your output directory.
183+
184+
Now it's a simple pip/uv dependency:
185+
186+
```bash
187+
# Install with pip
188+
pip install fable-library
189+
190+
# Or with uv (recommended)
191+
uv add fable-library
192+
```
193+
194+
:::info
195+
You can learn more about Fable.Python in general in our [documentation](https://fable.io/docs/python/build-and-run.html) or in this [blog post](https://cardamomcode.dev/fable-python#heading-introduction-to-fablepython)
196+
:::
197+
198+
## Rust
199+
200+
The Rust target kept improving as ell, and is now using Rust 2024 language edition.
201+
202+
## Hello Erlang/BEAM !
203+
204+
Dag Brattli added a new target for Erlang/BEAM, which is still in its early stages.
205+
206+
He has been testing it using [Fable.Giraffe](https://github.com/dbrattli/Fable.Giraffe) and the first results are promising:
207+
208+
> ## Benchmarks
209+
>
210+
> Simple `/ping` endpoint returning "pong", 10,000 requests with 100 concurrent
211+
> connections (oha):
212+
>
213+
> | Metric | BEAM | .NET | Python |
214+
> |---|---|---|---|
215+
> | Requests/sec | 124,256 | 70,375 | 4,006 |
216+
> | Avg latency | 0.79 ms | 1.40 ms | 24.9 ms |
217+
> | P99 latency | 2.49 ms | 3.50 ms | 34.2 ms |
218+
219+
Indeed, it seems like Erlang/BEAM is a great target for Fable, and we are excited to see how it evolves in the future.
220+
221+
## Conclusion
222+
223+
Fable 5 would not have been possible without the help of the many people who contributed to it in different ways, from testing, to reporting issues, to contributing code.
224+
225+
Thank you all for your help and support over the last year, and we hope you will continue to help us in the future to make Fable even better!

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
2+
"name": "fable-compiler.github.io",
23
"private": true,
34
"engines": {
45
"node": ">=14.0.0",

0 commit comments

Comments
 (0)