diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index fb6fd867a16..49d59cf9adb 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -2125,7 +2125,7 @@ impl ModCollector<'_, '_> {
 
         let is_export = export_attr.exists();
         let local_inner = if is_export {
-            export_attr.tt_values().flat_map(|it| &it.token_trees).any(|it| match it {
+            export_attr.tt_values().flat_map(|it| it.token_trees.iter()).any(|it| match it {
                 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
                     ident.text.contains("local_inner_macros")
                 }
diff --git a/crates/hir-expand/src/attrs.rs b/crates/hir-expand/src/attrs.rs
index c20c1639e1a..1c92dea38e6 100644
--- a/crates/hir-expand/src/attrs.rs
+++ b/crates/hir-expand/src/attrs.rs
@@ -123,7 +123,7 @@ impl RawAttrs {
                 .filter_map(|(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx)));
 
             let cfg_options = &crate_graph[krate].cfg_options;
-            let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() };
+            let cfg = Subtree { delimiter: subtree.delimiter, token_trees: Box::from(cfg) };
             let cfg = CfgExpr::parse(&cfg);
             if cfg_options.check(&cfg) == Some(false) {
                 smallvec![]
diff --git a/crates/hir-expand/src/builtin_attr_macro.rs b/crates/hir-expand/src/builtin_attr_macro.rs
index dd2aa94ad01..903b0d48070 100644
--- a/crates/hir-expand/src/builtin_attr_macro.rs
+++ b/crates/hir-expand/src/builtin_attr_macro.rs
@@ -137,5 +137,8 @@ pub fn pseudo_derive_attr_expansion(
         token_trees.extend(tt.iter().cloned());
         token_trees.push(mk_leaf(']'));
     }
-    ExpandResult::ok(tt::Subtree { delimiter: tt.delimiter, token_trees })
+    ExpandResult::ok(tt::Subtree {
+        delimiter: tt.delimiter,
+        token_trees: token_trees.into_boxed_slice(),
+    })
 }
diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs
index 29d389f656f..8d60f58628c 100644
--- a/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/crates/hir-expand/src/builtin_fn_macro.rs
@@ -155,10 +155,10 @@ fn line_expand(
     // not incremental
     ExpandResult::ok(tt::Subtree {
         delimiter: tt::Delimiter::invisible_spanned(span),
-        token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
+        token_trees: Box::new([tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
             text: "0u32".into(),
             span,
-        }))],
+        }))]),
     })
 }
 
@@ -208,11 +208,11 @@ fn assert_expand(
         [cond, panic_args @ ..] => {
             let comma = tt::Subtree {
                 delimiter: tt::Delimiter::invisible_spanned(call_site_span),
-                token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
+                token_trees: Box::new([tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
                     char: ',',
                     spacing: tt::Spacing::Alone,
                     span: call_site_span,
-                }))],
+                }))]),
             };
             let cond = cond.clone();
             let panic_args = itertools::Itertools::intersperse(panic_args.iter().cloned(), comma);
@@ -359,7 +359,10 @@ fn panic_expand(
         close: call_site_span,
         kind: tt::DelimiterKind::Parenthesis,
     };
-    call.token_trees.push(tt::TokenTree::Subtree(subtree));
+
+    // FIXME(slow): quote! have a way to expand to builder to make this a vec!
+    call.push(tt::TokenTree::Subtree(subtree));
+
     ExpandResult::ok(call)
 }
 
@@ -388,7 +391,10 @@ fn unreachable_expand(
         close: call_site_span,
         kind: tt::DelimiterKind::Parenthesis,
     };
-    call.token_trees.push(tt::TokenTree::Subtree(subtree));
+
+    // FIXME(slow): quote! have a way to expand to builder to make this a vec!
+    call.push(tt::TokenTree::Subtree(subtree));
+
     ExpandResult::ok(call)
 }
 
@@ -675,10 +681,10 @@ fn include_bytes_expand(
     // FIXME: actually read the file here if the user asked for macro expansion
     let res = tt::Subtree {
         delimiter: tt::Delimiter::invisible_spanned(span),
-        token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
+        token_trees: Box::new([tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
             text: r#"b"""#.into(),
             span,
-        }))],
+        }))]),
     };
     ExpandResult::ok(res)
 }
diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs
index f220284fae7..d5a1a14099e 100644
--- a/crates/hir-expand/src/db.rs
+++ b/crates/hir-expand/src/db.rs
@@ -524,7 +524,7 @@ fn macro_expand(
                 return ExpandResult {
                     value: CowArc::Owned(tt::Subtree {
                         delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
-                        token_trees: Vec::new(),
+                        token_trees: Box::new([]),
                     }),
                     // FIXME: We should make sure to enforce an invariant that invalid macro
                     // calls do not reach this call path!
@@ -586,7 +586,7 @@ fn macro_expand(
             return value.map(|()| {
                 CowArc::Owned(tt::Subtree {
                     delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
-                    token_trees: vec![],
+                    token_trees: Box::new([]),
                 })
             });
         }
@@ -601,7 +601,7 @@ fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<A
         return ExpandResult {
             value: Arc::new(tt::Subtree {
                 delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
-                token_trees: Vec::new(),
+                token_trees: Box::new([]),
             }),
             // FIXME: We should make sure to enforce an invariant that invalid macro
             // calls do not reach this call path!
@@ -635,7 +635,7 @@ fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<A
         return value.map(|()| {
             Arc::new(tt::Subtree {
                 delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
-                token_trees: vec![],
+                token_trees: Box::new([]),
             })
         });
     }
diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs
index 492501f5b6e..a3b2c700ffe 100644
--- a/crates/hir-expand/src/fixup.rs
+++ b/crates/hir-expand/src/fixup.rs
@@ -312,7 +312,7 @@ pub(crate) fn reverse_fixups(tt: &mut Subtree, undo_info: &SyntaxFixupUndoInfo)
 }
 
 fn reverse_fixups_(tt: &mut Subtree, undo_info: &[Subtree]) {
-    let tts = std::mem::take(&mut tt.token_trees);
+    let tts = std::mem::take(&mut tt.token_trees).into_vec();
     tt.token_trees = tts
         .into_iter()
         // delete all fake nodes
@@ -343,7 +343,7 @@ fn reverse_fixups_(tt: &mut Subtree, undo_info: &[Subtree]) {
                     // we have a fake node here, we need to replace it again with the original
                     let original = undo_info[u32::from(leaf.span().range.start()) as usize].clone();
                     if original.delimiter.kind == tt::DelimiterKind::Invisible {
-                        original.token_trees.into()
+                        SmallVec::from(original.token_trees.into_vec())
                     } else {
                         SmallVec::from_const([original.into()])
                     }
@@ -383,7 +383,7 @@ mod tests {
     fn check_subtree_eq(a: &tt::Subtree, b: &tt::Subtree) -> bool {
         a.delimiter.kind == b.delimiter.kind
             && a.token_trees.len() == b.token_trees.len()
-            && a.token_trees.iter().zip(&b.token_trees).all(|(a, b)| check_tt_eq(a, b))
+            && a.token_trees.iter().zip(b.token_trees.iter()).all(|(a, b)| check_tt_eq(a, b))
     }
 
     fn check_tt_eq(a: &tt::TokenTree, b: &tt::TokenTree) -> bool {
diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs
index bd250524903..2d29af287fe 100644
--- a/crates/hir-expand/src/lib.rs
+++ b/crates/hir-expand/src/lib.rs
@@ -66,6 +66,7 @@ pub mod tt {
     pub type Delimiter = ::tt::Delimiter<Span>;
     pub type DelimSpan = ::tt::DelimSpan<Span>;
     pub type Subtree = ::tt::Subtree<Span>;
+    pub type SubtreeBuilder = ::tt::SubtreeBuilder<Span>;
     pub type Leaf = ::tt::Leaf<Span>;
     pub type Literal = ::tt::Literal<Span>;
     pub type Punct = ::tt::Punct<Span>;
@@ -760,7 +761,7 @@ impl ExpansionInfo {
             (
                 Arc::new(tt::Subtree {
                     delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
-                    token_trees: Vec::new(),
+                    token_trees: Box::new([]),
                 }),
                 SyntaxFixupUndoInfo::NONE,
             )
diff --git a/crates/hir-expand/src/quote.rs b/crates/hir-expand/src/quote.rs
index 824f3c3e8f2..c1930c94f5c 100644
--- a/crates/hir-expand/src/quote.rs
+++ b/crates/hir-expand/src/quote.rs
@@ -31,7 +31,7 @@ macro_rules! __quote {
                     open: $span,
                     close: $span,
                 },
-                token_trees: $crate::quote::IntoTt::to_tokens(children),
+                token_trees: $crate::quote::IntoTt::to_tokens(children).into_boxed_slice(),
             }
         }
     };
@@ -146,7 +146,7 @@ impl IntoTt for Vec<crate::tt::TokenTree> {
     fn to_subtree(self, span: Span) -> crate::tt::Subtree {
         crate::tt::Subtree {
             delimiter: crate::tt::Delimiter::invisible_spanned(span),
-            token_trees: self,
+            token_trees: self.into_boxed_slice(),
         }
     }
 
@@ -296,8 +296,9 @@ mod tests {
         // }
         let struct_name = mk_ident("Foo");
         let fields = [mk_ident("name"), mk_ident("id")];
-        let fields =
-            fields.iter().flat_map(|it| quote!(DUMMY =>#it: self.#it.clone(), ).token_trees);
+        let fields = fields
+            .iter()
+            .flat_map(|it| quote!(DUMMY =>#it: self.#it.clone(), ).token_trees.into_vec());
 
         let list = crate::tt::Subtree {
             delimiter: crate::tt::Delimiter {
diff --git a/crates/mbe/src/benchmark.rs b/crates/mbe/src/benchmark.rs
index 6c3917b37f1..d946ecc1caf 100644
--- a/crates/mbe/src/benchmark.rs
+++ b/crates/mbe/src/benchmark.rs
@@ -100,17 +100,19 @@ fn invocation_fixtures(
                 // So we just skip any error cases and try again
                 let mut try_cnt = 0;
                 loop {
-                    let mut subtree = tt::Subtree {
+                    let mut token_trees = Vec::new();
+                    for op in rule.lhs.iter() {
+                        collect_from_op(op, &mut token_trees, &mut seed);
+                    }
+
+                    let subtree = tt::Subtree {
                         delimiter: tt::Delimiter {
                             open: DUMMY,
                             close: DUMMY,
                             kind: tt::DelimiterKind::Invisible,
                         },
-                        token_trees: vec![],
+                        token_trees: token_trees.into_boxed_slice(),
                     };
-                    for op in rule.lhs.iter() {
-                        collect_from_op(op, &mut subtree, &mut seed);
-                    }
                     if it.expand(&subtree, |_| (), true, DUMMY).err.is_none() {
                         res.push((name.clone(), subtree));
                         break;
@@ -127,45 +129,45 @@ fn invocation_fixtures(
 
     fn collect_from_op(
         op: &Op<DummyTestSpanData>,
-        parent: &mut tt::Subtree<DummyTestSpanData>,
+        token_trees: &mut Vec<tt::TokenTree<DummyTestSpanData>>,
         seed: &mut usize,
     ) {
         return match op {
             Op::Var { kind, .. } => match kind.as_ref() {
-                Some(MetaVarKind::Ident) => parent.token_trees.push(make_ident("foo")),
-                Some(MetaVarKind::Ty) => parent.token_trees.push(make_ident("Foo")),
-                Some(MetaVarKind::Tt) => parent.token_trees.push(make_ident("foo")),
-                Some(MetaVarKind::Vis) => parent.token_trees.push(make_ident("pub")),
-                Some(MetaVarKind::Pat) => parent.token_trees.push(make_ident("foo")),
-                Some(MetaVarKind::Path) => parent.token_trees.push(make_ident("foo")),
-                Some(MetaVarKind::Literal) => parent.token_trees.push(make_literal("1")),
-                Some(MetaVarKind::Expr) => parent.token_trees.push(make_ident("foo")),
+                Some(MetaVarKind::Ident) => token_trees.push(make_ident("foo")),
+                Some(MetaVarKind::Ty) => token_trees.push(make_ident("Foo")),
+                Some(MetaVarKind::Tt) => token_trees.push(make_ident("foo")),
+                Some(MetaVarKind::Vis) => token_trees.push(make_ident("pub")),
+                Some(MetaVarKind::Pat) => token_trees.push(make_ident("foo")),
+                Some(MetaVarKind::Path) => token_trees.push(make_ident("foo")),
+                Some(MetaVarKind::Literal) => token_trees.push(make_literal("1")),
+                Some(MetaVarKind::Expr) => token_trees.push(make_ident("foo")),
                 Some(MetaVarKind::Lifetime) => {
-                    parent.token_trees.push(make_punct('\''));
-                    parent.token_trees.push(make_ident("a"));
+                    token_trees.push(make_punct('\''));
+                    token_trees.push(make_ident("a"));
                 }
                 Some(MetaVarKind::Block) => {
-                    parent.token_trees.push(make_subtree(tt::DelimiterKind::Brace, None))
+                    token_trees.push(make_subtree(tt::DelimiterKind::Brace, None))
                 }
                 Some(MetaVarKind::Item) => {
-                    parent.token_trees.push(make_ident("fn"));
-                    parent.token_trees.push(make_ident("foo"));
-                    parent.token_trees.push(make_subtree(tt::DelimiterKind::Parenthesis, None));
-                    parent.token_trees.push(make_subtree(tt::DelimiterKind::Brace, None));
+                    token_trees.push(make_ident("fn"));
+                    token_trees.push(make_ident("foo"));
+                    token_trees.push(make_subtree(tt::DelimiterKind::Parenthesis, None));
+                    token_trees.push(make_subtree(tt::DelimiterKind::Brace, None));
                 }
                 Some(MetaVarKind::Meta) => {
-                    parent.token_trees.push(make_ident("foo"));
-                    parent.token_trees.push(make_subtree(tt::DelimiterKind::Parenthesis, None));
+                    token_trees.push(make_ident("foo"));
+                    token_trees.push(make_subtree(tt::DelimiterKind::Parenthesis, None));
                 }
 
                 None => (),
                 Some(kind) => panic!("Unhandled kind {kind:?}"),
             },
-            Op::Literal(it) => parent.token_trees.push(tt::Leaf::from(it.clone()).into()),
-            Op::Ident(it) => parent.token_trees.push(tt::Leaf::from(it.clone()).into()),
+            Op::Literal(it) => token_trees.push(tt::Leaf::from(it.clone()).into()),
+            Op::Ident(it) => token_trees.push(tt::Leaf::from(it.clone()).into()),
             Op::Punct(puncts) => {
                 for punct in puncts {
-                    parent.token_trees.push(tt::Leaf::from(*punct).into());
+                    token_trees.push(tt::Leaf::from(*punct).into());
                 }
             }
             Op::Repeat { tokens, kind, separator } => {
@@ -177,20 +179,20 @@ fn invocation_fixtures(
                 };
                 for i in 0..cnt {
                     for it in tokens.iter() {
-                        collect_from_op(it, parent, seed);
+                        collect_from_op(it, token_trees, seed);
                     }
                     if i + 1 != cnt {
                         if let Some(sep) = separator {
                             match sep {
                                 Separator::Literal(it) => {
-                                    parent.token_trees.push(tt::Leaf::Literal(it.clone()).into())
+                                    token_trees.push(tt::Leaf::Literal(it.clone()).into())
                                 }
                                 Separator::Ident(it) => {
-                                    parent.token_trees.push(tt::Leaf::Ident(it.clone()).into())
+                                    token_trees.push(tt::Leaf::Ident(it.clone()).into())
                                 }
                                 Separator::Puncts(puncts) => {
                                     for it in puncts {
-                                        parent.token_trees.push(tt::Leaf::Punct(*it).into())
+                                        token_trees.push(tt::Leaf::Punct(*it).into())
                                     }
                                 }
                             };
@@ -199,11 +201,15 @@ fn invocation_fixtures(
                 }
             }
             Op::Subtree { tokens, delimiter } => {
-                let mut subtree = tt::Subtree { delimiter: *delimiter, token_trees: Vec::new() };
+                let mut subtree = Vec::new();
                 tokens.iter().for_each(|it| {
                     collect_from_op(it, &mut subtree, seed);
                 });
-                parent.token_trees.push(subtree.into());
+
+                let subtree =
+                    tt::Subtree { delimiter: *delimiter, token_trees: subtree.into_boxed_slice() };
+
+                token_trees.push(subtree.into());
             }
             Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Length { .. } => {}
         };
@@ -230,7 +236,7 @@ fn invocation_fixtures(
         ) -> tt::TokenTree<DummyTestSpanData> {
             tt::Subtree {
                 delimiter: tt::Delimiter { open: DUMMY, close: DUMMY, kind },
-                token_trees: token_trees.unwrap_or_default(),
+                token_trees: token_trees.map(Vec::into_boxed_slice).unwrap_or_default(),
             }
             .into()
         }
diff --git a/crates/mbe/src/expander.rs b/crates/mbe/src/expander.rs
index 60483809dc1..9366048fd95 100644
--- a/crates/mbe/src/expander.rs
+++ b/crates/mbe/src/expander.rs
@@ -58,7 +58,7 @@ pub(crate) fn expand_rules<S: Span>(
         ExpandResult::new(
             tt::Subtree {
                 delimiter: tt::Delimiter::invisible_spanned(call_site),
-                token_trees: vec![],
+                token_trees: Box::new([]),
             },
             ExpandError::NoMatchingRule,
         )
diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs
index 40b4c7cdd65..eea92cfba4c 100644
--- a/crates/mbe/src/expander/matcher.rs
+++ b/crates/mbe/src/expander/matcher.rs
@@ -798,7 +798,7 @@ fn match_meta_var<S: Span>(
                 tt.map(|tt| match tt {
                     tt::TokenTree::Leaf(leaf) => tt::Subtree {
                         delimiter: tt::Delimiter::invisible_spanned(*leaf.span()),
-                        token_trees: vec![leaf.into()],
+                        token_trees: Box::new([leaf.into()]),
                     },
                     tt::TokenTree::Subtree(mut s) => {
                         if s.delimiter.kind == tt::DelimiterKind::Invisible {
@@ -832,7 +832,7 @@ fn match_meta_var<S: Span>(
                                 None => lit.into(),
                                 Some(neg) => tt::TokenTree::Subtree(tt::Subtree {
                                     delimiter: tt::Delimiter::invisible_spanned(*literal.span()),
-                                    token_trees: vec![neg, lit.into()],
+                                    token_trees: Box::new([neg, lit.into()]),
                                 }),
                             }
                         })
@@ -989,10 +989,10 @@ impl<S: Span> TtIter<'_, S> {
                 close: ident.span,
                 kind: tt::DelimiterKind::Invisible,
             },
-            token_trees: vec![
+            token_trees: Box::new([
                 tt::Leaf::Punct(*punct).into(),
                 tt::Leaf::Ident(ident.clone()).into(),
-            ],
+            ]),
         }
         .into())
     }
diff --git a/crates/mbe/src/expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs
index 800bc994ada..9291f799cca 100644
--- a/crates/mbe/src/expander/transcriber.rs
+++ b/crates/mbe/src/expander/transcriber.rs
@@ -83,7 +83,7 @@ impl<S: Span> Bindings<S> {
                             close: span,
                             kind: tt::DelimiterKind::Brace,
                         },
-                        token_trees: vec![],
+                        token_trees: Box::new([]),
                     })),
                     // FIXME: Meta and Item should get proper defaults
                     MetaVarKind::Meta | MetaVarKind::Item | MetaVarKind::Tt | MetaVarKind::Vis => {
@@ -349,11 +349,11 @@ fn expand_var<S: Span>(
             // We just treat it a normal tokens
             let tt = tt::Subtree {
                 delimiter: tt::Delimiter::invisible_spanned(id),
-                token_trees: vec![
+                token_trees: Box::new([
                     tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone, span: id })
                         .into(),
                     tt::Leaf::from(tt::Ident { text: v.clone(), span: id }).into(),
-                ],
+                ]),
             }
             .into();
             ExpandResult::ok(Fragment::Tokens(tt))
@@ -406,7 +406,7 @@ fn expand_repeat<S: Span>(
                 value: Fragment::Tokens(
                     tt::Subtree {
                         delimiter: tt::Delimiter::invisible_spanned(ctx.call_site),
-                        token_trees: vec![],
+                        token_trees: Box::new([]),
                     }
                     .into(),
                 ),
@@ -455,7 +455,7 @@ fn expand_repeat<S: Span>(
     // e.g {Delimiter:None> ['>'] /Delimiter:None>}
     let tt = tt::Subtree {
         delimiter: tt::Delimiter::invisible_spanned(ctx.call_site),
-        token_trees: buf,
+        token_trees: buf.into_boxed_slice(),
     }
     .into();
 
@@ -486,7 +486,7 @@ fn push_fragment<S: Span>(
 
 fn push_subtree<S>(buf: &mut Vec<tt::TokenTree<S>>, tt: tt::Subtree<S>) {
     match tt.delimiter.kind {
-        tt::DelimiterKind::Invisible => buf.extend(tt.token_trees),
+        tt::DelimiterKind::Invisible => buf.extend(Vec::from(tt.token_trees)),
         _ => buf.push(tt.into()),
     }
 }
@@ -504,7 +504,7 @@ fn fix_up_and_push_path_tt<S: Span>(
     // Note that we only need to fix up the top-level `TokenTree`s because the
     // context of the paths in the descendant `Subtree`s won't be changed by the
     // mbe transcription.
-    for tt in subtree.token_trees {
+    for tt in Vec::from(subtree.token_trees) {
         if prev_was_ident {
             // Pedantically, `(T) -> U` in `FnOnce(T) -> U` is treated as a generic
             // argument list and thus needs `::` between it and `FnOnce`. However in
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index d6c3bd18926..b1c83cf422c 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -130,7 +130,7 @@ where
         tt::Subtree {
             delimiter: tt::Delimiter { kind: tt::DelimiterKind::Invisible, .. },
             token_trees,
-        } => TokenBuffer::from_tokens(token_trees.as_slice()),
+        } => TokenBuffer::from_tokens(token_trees),
         _ => TokenBuffer::from_subtree(tt),
     };
     let parser_input = to_parser_input(&buffer);
@@ -227,14 +227,14 @@ where
     C: TokenConverter<S>,
     S: Span,
 {
-    let entry = tt::Subtree {
+    let entry = tt::SubtreeBuilder {
         delimiter: tt::Delimiter::invisible_spanned(conv.call_site()),
         token_trees: vec![],
     };
     let mut stack = NonEmptyVec::new(entry);
 
     while let Some((token, abs_range)) = conv.bump() {
-        let tt::Subtree { delimiter, token_trees } = stack.last_mut();
+        let tt::SubtreeBuilder { delimiter, token_trees } = stack.last_mut();
 
         let tt = match token.as_leaf() {
             Some(leaf) => tt::TokenTree::Leaf(leaf.clone()),
@@ -260,7 +260,7 @@ where
                     if matches!(expected, Some(expected) if expected == kind) {
                         if let Some(mut subtree) = stack.pop() {
                             subtree.delimiter.close = conv.span_for(abs_range);
-                            stack.last_mut().token_trees.push(subtree.into());
+                            stack.last_mut().token_trees.push(subtree.build().into());
                         }
                         continue;
                     }
@@ -275,7 +275,7 @@ where
                     // Start a new subtree
                     if let Some(kind) = delim {
                         let open = conv.span_for(abs_range);
-                        stack.push(tt::Subtree {
+                        stack.push(tt::SubtreeBuilder {
                             delimiter: tt::Delimiter {
                                 open,
                                 // will be overwritten on subtree close above
@@ -361,7 +361,7 @@ where
         parent.token_trees.extend(entry.token_trees);
     }
 
-    let subtree = stack.into_last();
+    let subtree = stack.into_last().build();
     if let [tt::TokenTree::Subtree(first)] = &*subtree.token_trees {
         first.clone()
     } else {
@@ -454,7 +454,7 @@ fn convert_doc_comment<S: Copy>(
     };
 
     // Make `doc="\" Comments\""
-    let meta_tkns = vec![mk_ident("doc"), mk_punct('='), mk_doc_literal(&comment)];
+    let meta_tkns = Box::new([mk_ident("doc"), mk_punct('='), mk_doc_literal(&comment)]);
 
     // Make `#![]`
     let mut token_trees = Vec::with_capacity(3);
diff --git a/crates/mbe/src/tt_iter.rs b/crates/mbe/src/tt_iter.rs
index 71513ef4391..f9913cb6f9b 100644
--- a/crates/mbe/src/tt_iter.rs
+++ b/crates/mbe/src/tt_iter.rs
@@ -180,7 +180,7 @@ impl<'a, S: Span> TtIter<'a, S> {
             [] | [_] => res.pop(),
             [first, ..] => Some(tt::TokenTree::Subtree(tt::Subtree {
                 delimiter: tt::Delimiter::invisible_spanned(first.first_span()),
-                token_trees: res,
+                token_trees: res.into_boxed_slice(),
             })),
         };
         ExpandResult { value: res, err }
diff --git a/crates/proc-macro-api/src/msg.rs b/crates/proc-macro-api/src/msg.rs
index e28fe387b84..aa5aff455fd 100644
--- a/crates/proc-macro-api/src/msg.rs
+++ b/crates/proc-macro-api/src/msg.rs
@@ -187,7 +187,67 @@ mod tests {
             file_id: FileId::from_raw(0),
             ast_id: ErasedFileAstId::from_raw(RawIdx::from(0)),
         };
-        let mut subtree = Subtree {
+
+        let token_trees = Box::new([
+            TokenTree::Leaf(
+                Ident {
+                    text: "struct".into(),
+                    span: Span {
+                        range: TextRange::at(TextSize::new(0), TextSize::of("struct")),
+                        anchor,
+                        ctx: SyntaxContextId::ROOT,
+                    },
+                }
+                .into(),
+            ),
+            TokenTree::Leaf(
+                Ident {
+                    text: "Foo".into(),
+                    span: Span {
+                        range: TextRange::at(TextSize::new(5), TextSize::of("Foo")),
+                        anchor,
+                        ctx: SyntaxContextId::ROOT,
+                    },
+                }
+                .into(),
+            ),
+            TokenTree::Leaf(Leaf::Literal(Literal {
+                text: "Foo".into(),
+
+                span: Span {
+                    range: TextRange::at(TextSize::new(8), TextSize::of("Foo")),
+                    anchor,
+                    ctx: SyntaxContextId::ROOT,
+                },
+            })),
+            TokenTree::Leaf(Leaf::Punct(Punct {
+                char: '@',
+                span: Span {
+                    range: TextRange::at(TextSize::new(11), TextSize::of('@')),
+                    anchor,
+                    ctx: SyntaxContextId::ROOT,
+                },
+                spacing: Spacing::Joint,
+            })),
+            TokenTree::Subtree(Subtree {
+                delimiter: Delimiter {
+                    open: Span {
+                        range: TextRange::at(TextSize::new(12), TextSize::of('{')),
+                        anchor,
+                        ctx: SyntaxContextId::ROOT,
+                    },
+                    close: Span {
+                        range: TextRange::at(TextSize::new(13), TextSize::of('}')),
+                        anchor,
+                        ctx: SyntaxContextId::ROOT,
+                    },
+                    kind: DelimiterKind::Brace,
+                },
+                token_trees: Box::new([]),
+            }),
+        ]);
+
+        Subtree {
             delimiter: Delimiter {
                 open: Span {
                     range: TextRange::empty(TextSize::new(0)),
@@ -201,65 +261,8 @@ mod tests {
                 },
                 kind: DelimiterKind::Invisible,
             },
-            token_trees: Vec::new(),
-        };
-        subtree.token_trees.push(TokenTree::Leaf(
-            Ident {
-                text: "struct".into(),
-                span: Span {
-                    range: TextRange::at(TextSize::new(0), TextSize::of("struct")),
-                    anchor,
-                    ctx: SyntaxContextId::ROOT,
-                },
-            }
-            .into(),
-        ));
-        subtree.token_trees.push(TokenTree::Leaf(
-            Ident {
-                text: "Foo".into(),
-                span: Span {
-                    range: TextRange::at(TextSize::new(5), TextSize::of("Foo")),
-                    anchor,
-                    ctx: SyntaxContextId::ROOT,
-                },
-            }
-            .into(),
-        ));
-        subtree.token_trees.push(TokenTree::Leaf(Leaf::Literal(Literal {
-            text: "Foo".into(),
-
-            span: Span {
-                range: TextRange::at(TextSize::new(8), TextSize::of("Foo")),
-                anchor,
-                ctx: SyntaxContextId::ROOT,
-            },
-        })));
-        subtree.token_trees.push(TokenTree::Leaf(Leaf::Punct(Punct {
-            char: '@',
-            span: Span {
-                range: TextRange::at(TextSize::new(11), TextSize::of('@')),
-                anchor,
-                ctx: SyntaxContextId::ROOT,
-            },
-            spacing: Spacing::Joint,
-        })));
-        subtree.token_trees.push(TokenTree::Subtree(Subtree {
-            delimiter: Delimiter {
-                open: Span {
-                    range: TextRange::at(TextSize::new(12), TextSize::of('{')),
-                    anchor,
-                    ctx: SyntaxContextId::ROOT,
-                },
-                close: Span {
-                    range: TextRange::at(TextSize::new(13), TextSize::of('}')),
-                    anchor,
-                    ctx: SyntaxContextId::ROOT,
-                },
-                kind: DelimiterKind::Brace,
-            },
-            token_trees: vec![],
-        }));
-        subtree
+            token_trees,
+        }
     }
 
     #[test]
diff --git a/crates/proc-macro-api/src/msg/flat.rs b/crates/proc-macro-api/src/msg/flat.rs
index 8dfaba52625..f2b2114679d 100644
--- a/crates/proc-macro-api/src/msg/flat.rs
+++ b/crates/proc-macro-api/src/msg/flat.rs
@@ -370,7 +370,7 @@ impl<'a, 'span, S: InternableSpan> Writer<'a, 'span, S> {
 
         self.subtree[idx].tt = [first_tt as u32, (first_tt + n_tt) as u32];
 
-        for child in &subtree.token_trees {
+        for child in subtree.token_trees.iter() {
             let idx_tag = match child {
                 tt::TokenTree::Subtree(it) => {
                     let idx = self.enqueue(it);
diff --git a/crates/proc-macro-srv/src/server/rust_analyzer_span.rs b/crates/proc-macro-srv/src/server/rust_analyzer_span.rs
index b864a5e4fd6..c7c7bea9941 100644
--- a/crates/proc-macro-srv/src/server/rust_analyzer_span.rs
+++ b/crates/proc-macro-srv/src/server/rust_analyzer_span.rs
@@ -104,7 +104,7 @@ impl server::TokenStream for RaSpanServer {
                     delimiter: delim_to_internal(group.delimiter, group.span),
                     token_trees: match group.stream {
                         Some(stream) => stream.into_iter().collect(),
-                        None => Vec::new(),
+                        None => Box::new([]),
                     },
                 };
                 let tree = tt::TokenTree::from(group);
@@ -221,7 +221,7 @@ impl server::TokenStream for RaSpanServer {
                     stream: if subtree.token_trees.is_empty() {
                         None
                     } else {
-                        Some(subtree.token_trees.into_iter().collect())
+                        Some(subtree.token_trees.into_vec().into_iter().collect())
                     },
                     span: bridge::DelimSpan::from_single(subtree.delimiter.open),
                 }),
diff --git a/crates/proc-macro-srv/src/server/token_id.rs b/crates/proc-macro-srv/src/server/token_id.rs
index c83e09af0d6..edbdc67b482 100644
--- a/crates/proc-macro-srv/src/server/token_id.rs
+++ b/crates/proc-macro-srv/src/server/token_id.rs
@@ -94,7 +94,7 @@ impl server::TokenStream for TokenIdServer {
                     delimiter: delim_to_internal(group.delimiter, group.span),
                     token_trees: match group.stream {
                         Some(stream) => stream.into_iter().collect(),
-                        None => Vec::new(),
+                        None => Box::new([]),
                     },
                 };
                 let tree = TokenTree::from(group);
@@ -206,7 +206,7 @@ impl server::TokenStream for TokenIdServer {
                     stream: if subtree.token_trees.is_empty() {
                         None
                     } else {
-                        Some(TokenStream { token_trees: subtree.token_trees })
+                        Some(TokenStream { token_trees: subtree.token_trees.into_vec() })
                     },
                     span: bridge::DelimSpan::from_single(subtree.delimiter.open),
                 }),
@@ -338,7 +338,7 @@ mod tests {
                         close: tt::TokenId(0),
                         kind: tt::DelimiterKind::Brace,
                     },
-                    token_trees: vec![],
+                    token_trees: Box::new([]),
                 }),
             ],
         };
@@ -354,10 +354,10 @@ mod tests {
                 close: tt::TokenId(0),
                 kind: tt::DelimiterKind::Parenthesis,
             },
-            token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
+            token_trees: Box::new([tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
                 text: "a".into(),
                 span: tt::TokenId(0),
-            }))],
+            }))]),
         });
 
         let t1 = TokenStream::from_str("(a)", tt::TokenId(0)).unwrap();
diff --git a/crates/proc-macro-srv/src/server/token_stream.rs b/crates/proc-macro-srv/src/server/token_stream.rs
index 8f669a30494..5edaa720fc7 100644
--- a/crates/proc-macro-srv/src/server/token_stream.rs
+++ b/crates/proc-macro-srv/src/server/token_stream.rs
@@ -15,14 +15,14 @@ impl<S> Default for TokenStream<S> {
 
 impl<S> TokenStream<S> {
     pub(crate) fn new() -> Self {
-        TokenStream { token_trees: vec![] }
+        TokenStream::default()
     }
 
     pub(crate) fn with_subtree(subtree: tt::Subtree<S>) -> Self {
         if subtree.delimiter.kind != tt::DelimiterKind::Invisible {
             TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] }
         } else {
-            TokenStream { token_trees: subtree.token_trees }
+            TokenStream { token_trees: subtree.token_trees.into_vec() }
         }
     }
 
@@ -36,7 +36,7 @@ impl<S> TokenStream<S> {
                 close: call_site,
                 kind: tt::DelimiterKind::Invisible,
             },
-            token_trees: self.token_trees,
+            token_trees: self.token_trees.into_boxed_slice(),
         }
     }
 
@@ -83,7 +83,7 @@ impl<S> Extend<TokenStream<S>> for TokenStream<S> {
                     tt::TokenTree::Subtree(subtree)
                         if subtree.delimiter.kind == tt::DelimiterKind::Invisible =>
                     {
-                        self.token_trees.extend(subtree.token_trees);
+                        self.token_trees.extend(subtree.token_trees.into_vec().into_iter());
                     }
                     _ => {
                         self.token_trees.push(tkn);
diff --git a/crates/test-fixture/src/lib.rs b/crates/test-fixture/src/lib.rs
index b5ff7a1bf51..cb8c36b680b 100644
--- a/crates/test-fixture/src/lib.rs
+++ b/crates/test-fixture/src/lib.rs
@@ -598,7 +598,7 @@ impl ProcMacroExpander for MirrorProcMacroExpander {
                 };
                 token_trees.push(tt);
             }
-            Subtree { delimiter: input.delimiter, token_trees }
+            Subtree { delimiter: input.delimiter, token_trees: token_trees.into_boxed_slice() }
         }
         Ok(traverse(input))
     }
diff --git a/crates/tt/src/buffer.rs b/crates/tt/src/buffer.rs
index cade2e9f67a..cd41af03c61 100644
--- a/crates/tt/src/buffer.rs
+++ b/crates/tt/src/buffer.rs
@@ -106,7 +106,7 @@ impl<'t, Span> TokenBuffer<'t, Span> {
 
         for (child_idx, (subtree, tt)) in children {
             let idx = TokenBuffer::new_inner(
-                subtree.token_trees.as_slice(),
+                &*subtree.token_trees,
                 buffers,
                 Some(EntryPtr(EntryId(res), child_idx + 1)),
             );
diff --git a/crates/tt/src/lib.rs b/crates/tt/src/lib.rs
index 83681c53397..b87c7ff4752 100644
--- a/crates/tt/src/lib.rs
+++ b/crates/tt/src/lib.rs
@@ -23,10 +23,10 @@ pub enum TokenTree<S> {
 }
 impl_from!(Leaf<S>, Subtree<S> for TokenTree);
 impl<S: Span> TokenTree<S> {
-    pub const fn empty(span: S) -> Self {
+    pub fn empty(span: S) -> Self {
         Self::Subtree(Subtree {
             delimiter: Delimiter::invisible_spanned(span),
-            token_trees: vec![],
+            token_trees: Box::new([]),
         })
     }
 
@@ -34,7 +34,7 @@ impl<S: Span> TokenTree<S> {
         match self {
             TokenTree::Leaf(_) => Subtree {
                 delimiter: Delimiter::invisible_delim_spanned(span),
-                token_trees: vec![self],
+                token_trees: Box::new([self]),
             },
             TokenTree::Subtree(s) => s,
         }
@@ -69,12 +69,35 @@ impl_from!(Literal<S>, Punct<S>, Ident<S> for Leaf);
 #[derive(Clone, PartialEq, Eq, Hash)]
 pub struct Subtree<S> {
     pub delimiter: Delimiter<S>,
-    pub token_trees: Vec<TokenTree<S>>,
+    pub token_trees: Box<[TokenTree<S>]>,
 }
 
 impl<S: Span> Subtree<S> {
-    pub const fn empty(span: DelimSpan<S>) -> Self {
-        Subtree { delimiter: Delimiter::invisible_delim_spanned(span), token_trees: vec![] }
+    pub fn empty(span: DelimSpan<S>) -> Self {
+        Subtree { delimiter: Delimiter::invisible_delim_spanned(span), token_trees: Box::new([]) }
+    }
+
+    /// This is slow, and should be avoided, as it will always reallocate!
+    pub fn push(&mut self, subtree: TokenTree<S>) {
+        let mut mutable_trees = std::mem::take(&mut self.token_trees).into_vec();
+
+        // Reserve exactly space for one element, to avoid `into_boxed_slice` having to reallocate again.
+        mutable_trees.reserve_exact(1);
+        mutable_trees.push(subtree);
+
+        self.token_trees = mutable_trees.into_boxed_slice();
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct SubtreeBuilder<S> {
+    pub delimiter: Delimiter<S>,
+    pub token_trees: Vec<TokenTree<S>>,
+}
+
+impl<S> SubtreeBuilder<S> {
+    pub fn build(self) -> Subtree<S> {
+        Subtree { delimiter: self.delimiter, token_trees: self.token_trees.into_boxed_slice() }
     }
 }
 
@@ -228,7 +251,7 @@ impl<S> fmt::Display for Subtree<S> {
         };
         f.write_str(l)?;
         let mut needs_space = false;
-        for tt in &self.token_trees {
+        for tt in self.token_trees.iter() {
             if needs_space {
                 f.write_str(" ")?;
             }
@@ -303,7 +326,7 @@ impl<S> Subtree<S> {
         let mut res = String::new();
         res.push_str(delim.0);
         let mut last = None;
-        for child in &self.token_trees {
+        for child in self.token_trees.iter() {
             let s = match child {
                 TokenTree::Leaf(it) => {
                     let s = match it {