diff --git a/include/fmt/format.h b/include/fmt/format.h
--- a/include/fmt/format.h
+++ b/include/fmt/format.h
@@ -28,16 +28,18 @@
   of this Software are embedded into a machine-executable object form of such
   source code, you may redistribute such embedded portions in such object form
   without including the above copyright and permission notices.
  */

 #ifndef FMT_FORMAT_H_
 #define FMT_FORMAT_H_

+#include "double-conversion/double-to-string.h"
+
 #ifndef _LIBCPP_REMOVE_TRANSITIVE_INCLUDES
 #  define _LIBCPP_REMOVE_TRANSITIVE_INCLUDES
 #  define FMT_REMOVE_TRANSITIVE_INCLUDES
 #endif

 #include "base.h"

 #ifndef FMT_MODULE
@@ -3141,16 +3143,23 @@ constexpr auto fractional_part_rounding_
   return U"\x9999999a\x828f5c29\x80418938\x80068db9\x8000a7c6\x800010c7"
          U"\x800001ae\x8000002b"[index];
 }

 template <typename Float>
 FMT_CONSTEXPR20 auto format_float(Float value, int precision,
                                   const format_specs& specs, bool binary32,
                                   buffer<char>& buf) -> int {
+  // GCC and old clang seem to hit this even though this function isn't called.
+  #ifdef __clang__
+  #if __clang_major__ >= 17
+    static_assert(false,
+      "This method is not to be used in Gecko, use format_float_gecko");
+  #endif
+  #endif
   // float is passed as double to reduce the number of instantiations.
   static_assert(!std::is_same<Float, float>::value, "");
   auto converted_value = convert_float(value);

   const bool fixed = specs.type() == presentation_type::fixed;
   if (value == 0) {
     if (precision <= 0 || !fixed) {
       buf.push_back('0');
@@ -3436,68 +3445,109 @@ FMT_CONSTEXPR20 auto format_float(Float
       --num_digits;
       ++exp;
     }
     buf.try_resize(num_digits);
   }
   return exp;
 }

+// See https://bugzilla.mozilla.org/show_bug.cgi?id=1717448#c2 for the reason
+// we're doing this. This copied from and should be kept in sync with
+// PrintfTarget::cvt_f in Gecko's mozglue/misc/Printf.cpp.
+template <typename Float>
+auto format_float_gecko(Float value, int precision, format_specs specs,
+                        buffer<char>& buf) -> int {
+  FMT_ASSERT(detail::isfinite(value),
+    "Non-finite values are to be handled ahead of calling this");
+  using double_conversion::DoubleToStringConverter;
+  using DTSC = DoubleToStringConverter;
+  // Printf.cpp seem to use UNIQUE_ZERO here, but then adds its own `-` further
+  // in the code.
+  char e = specs.upper() ? 'E' : 'e';
+  DTSC converter(DTSC::NO_TRAILING_ZERO |
+                 DTSC::EMIT_POSITIVE_EXPONENT_SIGN,
+                 "inf", "nan", e, 0, 0, 4, 0, 2);
+  buf.try_resize(64);
+  double_conversion::StringBuilder builder(buf.data(), buf.size());
+  // Negative precision defaults to 6.
+  if (precision == -1) { precision = 6; }
+  bool success = false;
+  if (specs.type() == presentation_type::exp) {
+      success = converter.ToExponential(value, precision, &builder);
+  } else if (specs.type() == presentation_type::fixed) {
+      success = converter.ToFixed(value, precision, &builder);
+  } else if (specs.type() == presentation_type::general ||
+      specs.type() == presentation_type::none) {
+      // "If an explicit precision is zero, it shall be taken as 1."
+      success = converter.ToPrecision(value, precision ? precision : 1, &builder);
+  } else {
+    FMT_ASSERT(false, "Unhandled");
+  }
+  FMT_ASSERT(success, "");
+  buf.try_resize(builder.position());
+  return builder.position();
+}
+
 template <typename Char, typename OutputIt, typename T>
 FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, format_specs specs,
                                  locale_ref loc) -> OutputIt {
   // Use signbit because value < 0 is false for NaN.
   sign s = detail::signbit(value) ? sign::minus : specs.sign();

   if (!detail::isfinite(value))
     return write_nonfinite<Char>(out, detail::isnan(value), specs, s);

   if (specs.align() == align::numeric && s != sign::none) {
     *out++ = detail::getsign<Char>(s);
     s = sign::none;
     if (specs.width != 0) --specs.width;
   }

   int precision = specs.precision;
-  if (precision < 0) {
-    if (specs.type() != presentation_type::none) {
-      precision = 6;
-    } else if (is_fast_float<T>::value && !is_constant_evaluated()) {
-      // Use Dragonbox for the shortest format.
-      using floaty = conditional_t<sizeof(T) >= sizeof(double), double, float>;
-      auto dec = dragonbox::to_decimal(static_cast<floaty>(value));
-      return write_float<Char>(out, dec, specs, s, loc);
-    }
-  }
-
   memory_buffer buffer;
   if (specs.type() == presentation_type::hexfloat) {
     if (s != sign::none) buffer.push_back(detail::getsign<char>(s));
     format_hexfloat(convert_float(value), specs, buffer);
     return write_bytes<Char, align::right>(out, {buffer.data(), buffer.size()},
                                            specs);
   }

   if (specs.type() == presentation_type::exp) {
-    if (precision == max_value<int>())
-      report_error("number is too big");
-    else
-      ++precision;
     if (specs.precision != 0) specs.set_alt();
   } else if (specs.type() == presentation_type::fixed) {
     if (specs.precision != 0) specs.set_alt();
   } else if (precision == 0) {
     precision = 1;
   }
-  int exp = format_float(convert_float(value), precision, specs,
-                         std::is_same<T, float>(), buffer);

   specs.precision = precision;
-  auto f = big_decimal_fp{buffer.data(), static_cast<int>(buffer.size()), exp};
-  return write_float<Char>(out, f, specs, s, loc);
+  value = abs(value);
+  format_float_gecko(convert_float(value), precision, specs, buffer);
+  size_t size = buffer.size();
+  if (s != sign::none) {
+    // Space for the sign, this influences the padding calculations below.
+    size++;
+    // If padding with zeros, the sign goes here, e.g. -0004.3
+    if (*specs.fill<Char>() == '0') {
+      *out++ = detail::getsign<Char>(s);
+    }
+  }
+  return write_padded<Char, align::right>(
+      out, specs, size, size, [s, &buffer, specs](reserve_iterator<OutputIt> it) {
+        // If padding with something other than zeros, the sign goes here, e.g.
+        // '   -4.3' (quotes added for clarity).
+        if (s != sign::none) {
+          if (*specs.fill<Char>() != '0') {
+            *it++ = detail::getsign<Char>(s);
+          }
+        }
+        const char* data = buffer.data();
+        return copy<Char>(data, data + buffer.size(), it);
+      });
 }

 template <typename Char, typename OutputIt, typename T,
           FMT_ENABLE_IF(is_floating_point<T>::value)>
 FMT_CONSTEXPR20 auto write(OutputIt out, T value, format_specs specs,
                            locale_ref loc = {}) -> OutputIt {
   return specs.localized() && write_loc(out, value, specs, loc)
              ? out
@@ -3513,18 +3563,17 @@ FMT_CONSTEXPR20 auto write(OutputIt out,

   constexpr auto specs = format_specs();
   using floaty = conditional_t<sizeof(T) >= sizeof(double), double, float>;
   using floaty_uint = typename dragonbox::float_info<floaty>::carrier_uint;
   floaty_uint mask = exponent_mask<floaty>();
   if ((bit_cast<floaty_uint>(value) & mask) == mask)
     return write_nonfinite<Char>(out, std::isnan(value), specs, s);

-  auto dec = dragonbox::to_decimal(static_cast<floaty>(value));
-  return write_float<Char>(out, dec, specs, s, {});
+  return write_float<Char>(out, value, specs, {});
 }

 template <typename Char, typename OutputIt, typename T,
           FMT_ENABLE_IF(is_floating_point<T>::value &&
                         !is_fast_float<T>::value)>
 inline auto write(OutputIt out, T value) -> OutputIt {
   return write<Char>(out, value, format_specs());
 }
