diff --git a/fontbe/src/os2.rs b/fontbe/src/os2.rs
index be53ed984..30753b10c 100644
--- a/fontbe/src/os2.rs
+++ b/fontbe/src/os2.rs
@@ -824,6 +824,7 @@ impl Work<Context, AnyWorkId, Error> for Os2Work {
         let codepoints = codepoints(context);
 
         let mut os2 = Os2 {
+            fs_type: static_metadata.misc.fs_type.unwrap_or_default(),
             ach_vend_id: static_metadata.misc.vendor_id,
             fs_selection: static_metadata.misc.selection_flags,
             x_avg_char_width: x_avg_char_width(context)?,
diff --git a/fontc/src/lib.rs b/fontc/src/lib.rs
index dcc4b6eb9..8a5eeb282 100644
--- a/fontc/src/lib.rs
+++ b/fontc/src/lib.rs
@@ -2432,4 +2432,27 @@ mod tests {
     fn compile_obeys_no_export_designspace() {
         assert_noexport("designspace_from_glyphs/WghtVar_NoExport.designspace");
     }
+
+    fn assert_fs_type(source: &str, expected_fs_type: u16) {
+        let temp_dir = tempdir().unwrap();
+        let build_dir = temp_dir.path();
+        compile(Args::for_test(build_dir, source));
+
+        let font_file = build_dir.join("font.ttf");
+        let buf = fs::read(font_file).unwrap();
+        let font = FontRef::new(&buf).unwrap();
+        let os2 = font.os2().unwrap();
+
+        assert_eq!(expected_fs_type, os2.fs_type());
+    }
+
+    #[test]
+    fn default_fs_type_glyphs() {
+        assert_fs_type("glyphs3/WghtVar.glyphs", 1 << 3);
+    }
+
+    #[test]
+    fn default_fs_type_designspace() {
+        assert_fs_type("designspace_from_glyphs/WghtVar.designspace", 1 << 2);
+    }
 }
diff --git a/fontir/src/ir.rs b/fontir/src/ir.rs
index 256f99a2f..014adae4e 100644
--- a/fontir/src/ir.rs
+++ b/fontir/src/ir.rs
@@ -82,6 +82,9 @@ pub struct StaticMetadata {
 #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(from = "MiscSerdeRepr", into = "MiscSerdeRepr")]
 pub struct MiscMetadata {
+    /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/os2#fstype>
+    pub fs_type: Option<u16>,
+
     /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/os2#fsselection>
     pub selection_flags: SelectionFlags,
 
@@ -285,6 +288,7 @@ impl StaticMetadata {
             default_location,
             postscript_names,
             misc: MiscMetadata {
+                fs_type: None, // default is, sigh, inconsistent across source formats
                 selection_flags: Default::default(),
                 vendor_id: DEFAULT_VENDOR_ID_TAG,
                 underline_thickness: 0.0.into(),
@@ -1566,6 +1570,7 @@ mod tests {
             ]),
             postscript_names: HashMap::from([("lhs".into(), "rhs".into())]),
             misc: MiscMetadata {
+                fs_type: None,
                 selection_flags: SelectionFlags::default(),
                 vendor_id: Tag::from_be_bytes(*b"DUCK"),
                 underline_thickness: 0.15.into(),
diff --git a/fontir/src/serde.rs b/fontir/src/serde.rs
index 428c16378..2f781f0a7 100644
--- a/fontir/src/serde.rs
+++ b/fontir/src/serde.rs
@@ -161,6 +161,7 @@ impl From<KerningSerdeRepr> for Kerning {
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
 pub(crate) struct MiscSerdeRepr {
+    pub fs_type: Option<u16>,
     pub selection_flags: u16,
     pub vendor_id: Tag,
     pub underline_thickness: f32,
@@ -175,6 +176,7 @@ pub(crate) struct MiscSerdeRepr {
 impl From<MiscSerdeRepr> for MiscMetadata {
     fn from(from: MiscSerdeRepr) -> Self {
         MiscMetadata {
+            fs_type: from.fs_type,
             selection_flags: SelectionFlags::from_bits_truncate(from.selection_flags),
             vendor_id: from.vendor_id,
             underline_thickness: from.underline_thickness.into(),
@@ -191,6 +193,7 @@ impl From<MiscSerdeRepr> for MiscMetadata {
 impl From<MiscMetadata> for MiscSerdeRepr {
     fn from(from: MiscMetadata) -> Self {
         MiscSerdeRepr {
+            fs_type: from.fs_type,
             selection_flags: from.selection_flags.bits(),
             vendor_id: from.vendor_id,
             underline_thickness: from.underline_thickness.into(),
diff --git a/glyphs2fontir/src/source.rs b/glyphs2fontir/src/source.rs
index 5a33c441b..6753bb68e 100644
--- a/glyphs2fontir/src/source.rs
+++ b/glyphs2fontir/src/source.rs
@@ -358,6 +358,10 @@ impl Work<Context, WorkId, WorkError> for StaticMetadataWork {
             static_metadata.misc.vendor_id =
                 Tag::from_str(vendor_id).map_err(WorkError::InvalidTag)?;
         }
+
+        // <https://github.com/googlefonts/glyphsLib/blob/cb8a4a914b0a33431f0a77f474bf57eec2f19bcc/Lib/glyphsLib/builder/custom_params.py#L1117-L1119>
+        static_metadata.misc.fs_type = Some(1 << 3);
+
         // <https://github.com/googlefonts/glyphsLib/blob/main/Lib/glyphsLib/builder/custom_params.py#L1116-L1125>
         static_metadata.misc.underline_thickness = 50.0.into();
         static_metadata.misc.underline_position = (-100.0).into();
diff --git a/ufo2fontir/src/source.rs b/ufo2fontir/src/source.rs
index ad247caf3..0c298d618 100644
--- a/ufo2fontir/src/source.rs
+++ b/ufo2fontir/src/source.rs
@@ -839,6 +839,9 @@ impl Work<Context, WorkId, WorkError> for StaticMetadataWork {
                 Tag::from_str(vendor_id).map_err(WorkError::InvalidTag)?;
         }
 
+        // <https://github.com/googlefonts/glyphsLib/blob/cb8a4a914b0a33431f0a77f474bf57eec2f19bcc/Lib/glyphsLib/builder/custom_params.py#L1117-L1119>
+        static_metadata.misc.fs_type = Some(1 << 2);
+
         // <https://github.com/googlefonts/ufo2ft/blob/main/Lib/ufo2ft/fontInfoData.py#L313-L322>
         static_metadata.misc.underline_thickness = font_info_at_default
             .postscript_underline_thickness