diff --git a/content/news/2023-10-21-bevy-0.12/index.md b/content/news/2023-10-21-bevy-0.12/index.md
index 5321faf913..f7ff3c1d6b 100644
--- a/content/news/2023-10-21-bevy-0.12/index.md
+++ b/content/news/2023-10-21-bevy-0.12/index.md
@@ -19,6 +19,85 @@ Since our last release a few months ago we've added a _ton_ of new features, bug
authors: @author
+## One-Shot Systems
+
+authors: @alice-i-cecile @pascualex, @Trashtalk217, @Zeenobit
+
+Ordinarily, systems run once per frame, as part of a schedule.
+But this isn't always the right fit.
+Maybe you're responding to a very rare event like in a complex turn-based game, or simply don't want to clutter your schedule with a new system for every single button.
+One-shot systems flip that logic on its head, and provide you the ability to run arbitrary logic on demand, using the powerful and familiar system syntax.
+
+```rust
+#[derive(Resource, Default, Debug)]
+struct Counter(u8);
+
+fn increment(mut counter: ResMut) {
+ counter.0 += 1;
+ println!("{}", counter.0);
+}
+
+fn foo(world: &mut World) {
+ world.init_resource::();
+ let id = world.register_system(increment);
+ let _ = world.run_system(id); // prints 1
+ let _ = world.run_system(id); // prints 2
+}
+```
+
+There are three simple steps to using one-shot systems: register a system, store its `SystemId`, and then use either exclusive world access or commands to run the corresponding system.
+
+A lot becomes possible with just that, however `SystemId`s really start showing their power, when they're wrapped into components.
+
+```rust
+use bevy::ecs::system::SystemId;
+
+#[derive(Component)]
+struct Callback(SystemId);
+
+// calling all callbacks!
+fn call_all(query: Query<&Callback>, mut commands: Commands) {
+ for callback in query.iter() {
+ commands.run_system(callback.0);
+ }
+}
+```
+
+One-shot systems can then be attached to UI elements, like buttons, actions in an RPG, or any other entity. You might even feel inspired to implement the bevy scheduling graph with one-shot systems and [`aery`](https://docs.rs/aery/latest/aery/) (let us know how that goes, by the way).
+
+One-shot systems are very flexible.
+They can be nested, so you can call `run_system` from within a one-shot system.
+It's possible to have multiple instances of one system registered at a time, each with their own `Local` variables and cached system state.
+It also plays nice with asset-driven workflows: recording a mapping from a string to an identifier in a serialized callback is much nicer than trying to do so with Rust functions!
+
+Still, one-shot systems are not without their limitations.
+Currently, exclusive systems and systems designed for system piping (with either an `In` parameter or a return type) can't be used at all.
+You also can't call a one-shot systems from itself, recursion isn't possible.
+Lastly, one-shot systems are always evaluated sequentially, rather than in parallel.
+While this reduces both complexity and overhead, for certain workloads this can be meaningfully slower than using a schedule with a parallel executor.
+
+However, when you're just prototyping or writing a unit test, it can be a real hassle: two whole functions and some weird identifier?
+For these situations, you can use the `World::run_system_once` method.
+
+```rust
+use bevy::ecs::system::RunSystemOnce;
+
+#[derive(Resource, Default, Debug)]
+struct Counter(u8);
+
+fn increment(mut counter: ResMut) {
+ counter.0 += 1;
+ println!("{}", counter.0);
+}
+
+let mut world = World::new();
+world.init_resource::();
+world.run_system_once(increment); // prints 1
+world.run_system_once(increment); // prints 2
+```
+
+This is great for unit testing systems and queries, and it's both lower overhead and simpler to use. However, there is one caveat. Some systems have state, either in the form of `Local` arguments, change detection, or `EventReader`s. This state isn't saved between two `run_system_once` calls, creating odd behavior. The `Local`s reset every run, while change detection will _always_ detect data as added/changed. Be careful and you'll be alright.
+
## What's Next?
We have plenty of work that is pretty much finished and is therefore very likely to land in **Bevy 0.13**: